[MAF Workflow编排模式-02]如何解决Sequential模式下前置节点越权执行的问题?

由于Sequential模式构建的Worflow由多一个AIAgent按照编排的顺序执行,前置节点越权执行是一个非常常见的现象。举个简单的例子,假设我们采用此模式构建一个包含如下三个Agent的Workflow:数据收集Agent、数据分析Agent和数据报告Agent,在调用时Workflow时我输入如下的任务:“提取最近三年手机三大品牌全球销量、然后通过分析数据生成一份销售报告,最终以邮件形式发出来”。貌似很合理对吧,但是会出现一个问题:完整的提示词的三部分其实是分别对三个Agent说的,但是完整的提示词直接传给了第一个Agent,导致第一个Agent越权执行了后续两个Agent的任务。虽然可以利用系统指令强行让每个Agent只关注自己负责的那一块,但是这样的做法并非每次都有效。

1. 前置节点把所有的事都干了

还记得前文演示的多体裁作品创作智能体的三个分别用于创作唐诗、宋词和短篇小说的三个AIAgent是如何创建的吗?如下面的代码所示,我们通过指定了系统指令让三个Agent各司其职,不要越界。

var tangPoetryComposer = CreateChatClient()
    .AsAIAgent(
    name: "TangPoetryComposer",
    instructions: """
    你是一个精通唐诗创作的智能体,负责根据提供的主题和意境创作一首符合唐诗风格的诗歌。
    如果用户的任务了提及了基于其他非唐诗(比如宋词、短篇小说)的创作,请忽略。
    """);
var songLyricsComposer = CreateChatClient()
    .AsAIAgent(
    name: "SongLyricsComposer",
    instructions: """
    你是一个精通宋词创作的智能体,负责根据提供的主题和意境创作一首宋词,你可以自选词牌名
    如果用户的任务了提及了基于其他非宋词(比如唐诗、短篇小说)的创作,请忽略。
    """);

var novelComposer = CreateChatClient()
    .AsAIAgent(
    name: "NovelComposer",
    instructions: """
    你是一个精通小说创作的智能体,负责根据提供的主题和意境创作一篇1000字以内的短篇小说。
    如果用户的任务了提及了基于其他非小说(比如唐诗、宋词)的创作,请忽略。
    """);

如果将对应的排他性指令文本去掉(第二句话)去掉后再次执行演示程序,就会出现如下的输出。从输出可以看出用于创建唐诗和小说的Agent都完成了三种体裁的创作。由于LLM的生成是基于概率的,所以每次执行的结果可能不一样,但是前置节点越权执行的现象是必然会出现的。而且及时我们添加了排他性指令,其实也不能保证每次执行都能有效。

--------------------TangPoetryComposer_1cb0e91144de43c7bbf145a3e0a0cd73--------------------
《弃妇吟》
淇水汤汤送旧人,桑叶飘零碾作尘。
昔时抱布情如蜜,今日挥鞭意似焚。
三秋甘受贫家苦,一夜翻成陌路嗔。
莫道红颜多薄命,从来白首负深恩。

《蝶恋花·秋桑叹》
犹记抱布春意逗,涉过淇滨,暗把终身就。桑葚垂枝红染袖,谁知鸠鸟啄心透。
黄叶西风凋碧后,贫贱夫妻,泪渍青衫皱。信誓如烟逐水流,残阳空照秋桑瘦。

《氓之变》
秋雨敲打着淇水河岸,阿蘅跪在泥泞里捡拾散落的蚕茧。三年前那个抱着布匹来换丝的男人,此刻正把她的妆奁往牛车上扔,镶铜的奁盒砸在青石上发出碎响。

“这些桑叶全喂了野蚕。”氓踢开竹匾,去年晒好的桑叶卷着霉斑滚进水洼。他腰间别着新换的玉钩,那是城西当铺李掌柜家闺女的陪嫁。阿蘅还记得三个月前,氓第一次穿上绸衫时,袖口掉出的鸳鸯锦帕。

淇水的浪头打湿了她的麻布裙裾,恍惚间变成成亲那日被抱上牛车时溅起的河水。那时氓的掌心贴着喜饼的油渍,许下的誓比顿丘的磐石还重。可三更天的织机声磨破了她的指尖,灶台的烟火熏哑了她的嗓子,却换来氓把算盘摔在她膝上:“三年就织了这些?”

最寒的不是秋风,是今早氓把休书拍在桌上的声响。泛黄的纸上列着她的罪状:无子、多言、炊米太费。她忽然想起母亲当年用桑葚汁给她染指甲时说:“斑鸠吃多了桑葚会醉死,女子贪恋情爱会碎心。”

牛车启动时,阿蘅攥住车辕:“你说过白头偕老的。”氓的鞭子抽在黄牛背上,声音比初冬的冰还脆:“淇水还有岸,隰地还有边,就你这怨气没个尽头。”

散落的蚕茧被车轮碾成絮,阿蘅突然笑了。她想起总角时和氓偷摘邻家桑葚,紫红的汁液染了满襟,那时他说要娶她,她笑得像三月的黄莺。如今才懂,斑鸠醉倒尚能醒,女子醉情终生误。

--------------------SongLyricsComposer_bde281621a5a408dbaee85b9f1e99640--------------------
《雨霖铃·秋桑叹》
秋霖初歇。对淇河晚,败叶堆雪。
残垣尚记凝望,烟波断处,归帆明灭。
总角青梅如昨,竟翻作长别。
算三载、机杼声寒,茧破丝空寸心裂。

斑鸠误啄桑葚血。更那堪、露重芳菲歇。
罗襦暗数针脚,针针是、旧年呜咽。
玉勒新鞍,谁见空奁碎珮,堕寒月。
纵觅得、隰泮淇涯,不是回春碣。

注:此词以《雨霖铃》为调,取秋雨初霁、桑林凋敝之象,暗合弃妇零落身世。上阕以“残垣凝望”勾连《氓》诗“乘彼垝垣”之境,“茧破丝空”喻三年辛劳成空。下阕化用“鸠食桑葚”典故,以“玉勒新鞍”对照“空奁碎珮”,凸显男子变心后的物质反差。结句借“隰泮淇涯”反用原诗,言纵有边界可寻,而人生无再少之春,较原诗“亦已焉哉”更添一层宿命悲怆。

--------------------NovelComposer_5aa12d37851d4a3194ed6c97b6cf7cbb--------------------
好的,依你之愿,我将为你呈现基于同一母题、却风格迥异的三篇创作。我们将先从唐诗的凝练哀婉,到宋词的深婉悱恻,最后步入短篇小说的幽微内心,层层递进,将《氓》中的千古悲歌娓娓道来。

---

### **唐诗·淇水别**

淇水汤汤送旧人,桑之落矣碾为尘。
垝垣曾望关山远,车马今来涕泪新。
三岁为劳甘食苦,一朝反目忍言嗔。
信誓旦旦终成幻,独向西风悼此身。

---

### **宋词·蝶恋花·秋桑叹**

犹记抱布春意逗,涉过淇滨,暗把终身就。桑叶沃若盈翠袖,谁知鸠鸟啄心透。

黄叶西风凋碧后,贫贱夫妻,泪渍青衫皱。信誓如烟逐水流,残阳空照秋桑瘦。

---

### **短篇小说·桑落**

阿蘅最后看一眼那个家时,院角的桑树正落下最后一片叶子。

叶子飘得很慢,在空中打了个旋,才不甘不愿地贴在湿漉漉的泥地上。她想起三年前,就是在这棵桑树下,氓用粗粝的手掌包着她的手,说要用最好的布来换她最好的丝。那时他的眼睛亮得像淇水上的星光,让她忘了母亲说过的话——斑鸠吃多了桑葚会醉,女子沉溺于情爱会碎心。

醉的是她。碎了的,也是她。

三更的织机声还响在耳畔。梭子来回穿梭,像永远走不到头的日子。她的手指被丝线勒出一道道血口,愈合,又裂开,最后结成层层叠叠的茧。氓说她织的布不够细密,说她煮的粥太稀,说她回娘家的次数太多。他的声音起初是失望,后来是不耐,最后变成了冰。

今早他把休书拍在桌上时,阿蘅正端着粥。粥碗晃了晃,几粒米溅在休书上,洇开了“无子”两个字。她盯着那两个字看了很久,久到氓的呵斥声都变成了嗡嗡的背景音。她只是在想,这三年里,哪个夜晚不是为了织布熬到天亮?哪顿饭不是先紧着他吃?哪句话不是小心着说,怕惹他皱眉?

可这些都不在休书上。

休书上写的是:无子,多言,炊米太费。

阿蘅突然想笑。她想问氓,你腰间那枚新换的玉钩,是用哪一匹布换的?你袖口掉出的那方鸳鸯锦帕,又是哪家姑娘的针脚?但她最终什么也没问,只是弯腰捡起粥碗的碎片。碎片扎进掌心,疼得清醒。

此刻她站在淇水边,看着氓把她的妆奁扔上牛车。奁盒砸在青石上,她母亲留下的那面铜镜滚了出来。她弯腰去捡,手指刚触到镜面,氓的鞭子抽在牛背上,车轮碾过铜镜,碾过她最后一寸念想。

“淇水还有岸,隰地还有边。”

氓的声音从车上飘下来,被秋风吹散。阿蘅攥着被碾出裂纹的铜镜,镜中映着她的脸——二十岁的面容,却像桑树落尽叶子的枝桠。

她忽然想起从前偷摘邻家桑葚的光景。氓爬树,她在树下兜着衣襟接。紫红的浆果噼里啪啦落下来,染得她满襟都是。氓从树上跳下来,摘了颗最饱满的塞进她嘴里,甜得她眯起眼睛笑。那时他说要娶她,她说好。两个总角小儿,把过家家当成了真的。

她竟忘了,过家家是可以散的。

桑葚的甜是醉人的。斑鸠醉倒了,尚能醒来。而她醉倒了,醒来时已是满目荒芜。

阿蘅抬起头,最后看了一眼远去的牛车。淇水汤汤向东流,岸边的芦苇在秋风里摇成一片苍黄。她把铜镜放进怀里,往娘家的方向走去。

走了七步,停下。

又走了七步,再停下。

不是因为留恋——只是因为风冷,露重,而她还没来得及学会,如何做一个不再回头的女人。

2. 通过提示词隔离的方式彻底解决前置节点越权执行

前置节点越权的问题根源在于让Agent看到了超越其任务范围的提示词信息。虽然系统指令具有最强的约束能力,但是具体听谁的还取决于具体的语言组织以及LLM自身的理解,说白了这是两种力量之间的对抗,谁胜谁负其实很难控制。要彻底就解决这个问题,唯有提示词隔离一种办法,也就是让每个Agent在执行时只能看到自己任务范围内的提示词信息,而看不到其他Agent的提示词信息。为此我重新定义了基于Sequential模式编排Workflow的BuildSequential方法。

static Workflow BuildSequential(params (AIAgent Agent, List<ChatMessage>? Messages)[] agentsWithInjectedMessages)

如上面的代码所示,我将原来的BuildSequential方法的参数类型从AIAgent列表改成了(AIAgent Agent, List<ChatMessage>? Messages)元组列表,也就是说可以我们在每个Agent执行后为后续Agent注入一组提示词信息。我们使用此方法重写了前面的演示程序:三个Agent的指令只关注自己负责的那一块,并且不再添加排他性的指令文本。在调用BuildSequential方法时,我们将针对宋词的创作任务注入到唐诗的Agent执行后,针对短篇小说的创作任务注入到宋词的Agent执行后。原始的提示词只提到了唐诗的创作任务。

using Azure;
using dotenv.net;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;
using OpenAI;

DotEnv.Load();

var tangPoetryComposer = CreateChatClient()
    .AsAIAgent(
    name: "TangPoetryComposer",
    instructions: """
    你是一个精通唐诗创作的智能体,负责根据提供的主题和意境创作一首符合唐诗风格的诗歌。
    """);
var songLyricsComposer = CreateChatClient()
    .AsAIAgent(
    name: "SongLyricsComposer",
    instructions: """
    你是一个精通宋词创作的智能体,负责根据提供的主题和意境创作一首宋词,你可以自选词牌名
    """);

var novelComposer = CreateChatClient()
    .AsAIAgent(
    name: "NovelComposer",
    instructions: """
    你是一个精通小说创作的智能体,负责根据提供的主题和意境创作一篇1000字以内的短篇小说。
    """);

var workflow = BuildSequential(
    (tangPoetryComposer, [new ChatMessage(ChatRole.User, "根据提供的诗歌《卫风·氓》的背景和情感基调创作一首宋词")]), 
    (songLyricsComposer, [new ChatMessage(ChatRole.User, "根据提供的诗歌《卫风·氓》的背景和情感基调创作一篇短篇小说")]), 
    (novelComposer, null));

var originalPoem = """    
    氓之蚩蚩,抱布贸丝。匪来贸丝,来即我谋。
    送子涉淇,至于顿丘。匪我愆期,子无良媒。
    将子无怒,秋以为期。
   
    乘彼垝垣,以望复关。不见复关,泣涕涟涟。
    既见复关,载笑载言。尔卜尔筮,体无咎言。
    以尔车来,以我贿迁。
  
    桑之未落,其叶沃若。于嗟鸠兮,无食桑葚!
    于嗟女兮,无与士耽!士之耽兮,犹可说也;
    女之耽兮,不可说也。
    
    桑之落矣,其黄而陨。自我徂尔,三岁食贫。
    淇水汤汤,渐车帷裳。女也不爽,士贰其行。
    士也罔极,二三其德。
    
    三岁为妇,靡室劳矣;夙兴夜寐,靡有朝矣。
    言既遂矣,至于暴怒。兄弟不知,咥其笑矣。
    静言思之,躬自悼矣。
   
    及尔偕老,老使我怨。淇则有岸,隰则有泮。
    总角之宴,言笑晏晏。信誓旦旦,不思其反。
    反是不思,亦已焉哉!    
    """;

var prompt = $"""
    基于如下这首《卫风·氓》的背景和情感基调创作一首唐诗。

    原文如下:
    {originalPoem}
    """;

await using (var run = await InProcessExecution.Default.RunStreamingAsync(workflow, prompt))
{
    await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
    string? lastExecutorId = null;
    await foreach (WorkflowEvent evt in run.WatchStreamAsync())
    {
        if (evt is AgentResponseUpdateEvent e)
        {
            if (e.ExecutorId != lastExecutorId)
            {
                lastExecutorId = e.ExecutorId;
                Console.WriteLine($"\n{new string('-', 20)}{e.ExecutorId}{new string('-', 20)}");
            }
            Console.Write(e.Update.Text);
        }
    }
}

IChatClient CreateChatClient()
{
    var model = Environment.GetEnvironmentVariable("MODEL")!;
    var apiKey = Environment.GetEnvironmentVariable("API_KEY")!;
    var endpoint = Environment.GetEnvironmentVariable("OPENAI_URL")!;

    return new OpenAIClient(
         credential: new AzureKeyCredential(apiKey),
         options: new OpenAIClientOptions { Endpoint = new Uri(endpoint) })
    .GetResponsesClient()
    .AsIChatClient(defaultModelId: model);
}

输出:

--------------------TangPoetryComposer_5744b9b6cc4647e19ac4af864b062572--------------------
《代卫风弃妇吟》
淇水汤汤送旧人,复关望断几回春。
盟言犹在耳,秋以为期信誓真。

三年夙夜侍蚕桑,罗帷未暖君心变。
鸠食桑葚不知醉,妾悔当初错认君。

--------------------SongLyricsComposer_779e58349c054b0ca3db128721799c68--------------------
《钗头凤·淇水寒》
淇水咽,秋期绝,复关残月音书灭。
蚕桑歇,罗帷裂,三年夙夜,一朝霜雪。
切!切!切!

鸠贪蜜,桑空碧,总角欢愉成追忆。
盟如屑,郎心铁,岸泮犹在,信誓虚设。
决!决!决!

注:此词以《卫风·氓》弃妇之怨为骨,取陆游唐婉词牌之体。上片以“淇水咽”起兴,呼应原诗“送子涉淇”之景,“秋期绝”暗藏“秋以为期”之誓成空。下片“鸠贪蜜”反用“无食桑葚”之诫,结句三重“决”字,既合原诗“亦已焉哉”之决绝,更添词体特有的顿挫呜咽之致,较之陆游唐婉的和词,另具《诗经》古拙风韵。

--------------------NovelComposer_01d47dcfc1e142a59136a6cbd3a6cd06--------------------
淇水边的桑树又落叶了。

我站在岸边,看着河水汤汤,恍惚间又看见当年那个抱着布匹的男子。他笑得憨厚,说是来买丝,眼睛却一直瞟着我。那时我以为这是命中注定的姻缘,傻傻地送他到顿丘,又傻傻地等了一个秋天。

复关的城墙我都爬了多少回了。每回望不见他的身影,就躲在垝垣后面掉眼泪。姐妹们笑话我痴,我只当她们不懂。后来他来了,带着占卜的吉兆,我高兴得什么似的,催着他赶快把车赶来,把我的嫁妆都搬走。

新婚那夜,他叫我“小桑叶”。他说我的脸颊像春天的桑叶一样嫩。我羞得直往他怀里钻,觉得自己是天底下最幸运的女子。

三年。整整三年。

鸡叫头遍我就起身,纺线织布到月上中天。他的手越来越懒,脾气却越来越大。我做的饭嫌淡,缝的衣裳嫌粗,就连走路的声音都嫌吵。有一次他喝了酒回来,抄起棍子就打,说我在外头勾搭别的男人。

我去找兄弟诉苦。哥哥们正在院子里喝酒,见我哭哭啼啼进来,先是一愣,继而哈哈大笑。

“早就叫你别嫁那个穷光蛋,你偏不听。”

“如今知道回来哭了?”

“嫁出去的女儿泼出去的水,你找我们有什么用?”

我站在堂屋中间,像一只落汤鸡。他们继续喝酒划拳,笑声震得屋顶的灰都往下掉。我退出来的时候,连门槛都差点绊我一跤。

那天夜里我又来到淇水边。河水还是那样流着,不急不缓,就像三年前我等他娶我的时候一样。可我知道,河水有岸,沼泽有边,我这份苦处却没个尽头。

他曾经说过要跟我白头到老的。那时候我们在河边捉蟋蟀,在桑林里采桑葚,他指天发誓说这辈子只对我一个人好。我当时信了,信得真真的,就像斑鸠贪吃桑葚一样,吃得醉醺醺,完全不知道醉过后是什么下场。

现在我知道了。

女人一旦陷进去,就再也出不来。男人说变就变,今天说爱你,明天就能把你当仇人。可女人不行,女人把自己整个儿都投进去了,等发现所托非人时,连魂都找不回来了。

河水还是汤汤地流。

我站起来,拍了拍裙上的土。既然誓言都成了空,那就算了吧。桑叶落了就落了,还能怎么着。

我最后看了一眼这条淇水。河面上飘着一片枯黄的桑叶,打着旋儿,慢慢沉了下去。

就像我这三年,就这么沉下去了。

回头的时候,风吹过来,冷得很。我把袖子拢了拢,往娘家方向走。路还是那条路,只是这世上再也没有“小桑叶”了。

有人可能会说,你这也没有完全隔离呀,写宋词的Agent还是看到了唐诗的创作任务呀,写小说的Agent还能同时看到了唐诗和宋词的创作任务呀。但是这反而是对的,因为Sequential模式下就是需要让后续节点在前序节点的成果基础上继续执行任务,虽然它看到了不属于自己任务范围的提示词信息,但是它也看到前序节点已经完成了各自的任务,加上系统指令的约束,它知道该做什么。

3. Sequential模式的消息注入

重写的BuildSequential方法本质上就是在每个AIAgent节点之后添加一个额外的节点实现了消息注入的功能。对于上面构建的Workflow,它具有如下的结构:

Alternative Text

3.1 MessageInjectingExecutor

Workflow中用来注入消息的Executor为如下这个MessageInjectingExecutor。它继承自ChatProtocolExecutor,所以可以成为采用Chat协议的数据流的一个标准的环节。它注入的消息通过构造函数提供的List<ChatMessage>对象来指定,并在重写的TakeTurnAsync方法中将累积和注入的消息一起发送出去。

public sealed class MessageInjectingExecutor(List<ChatMessage>? additionalMessages)
    : ChatProtocolExecutor("MessageInjecting"+Guid.NewGuid())
{    
    protected override async ValueTask TakeTurnAsync(
        List<ChatMessage> messages,
        IWorkflowContext context,
        bool? emitEvents,
        CancellationToken cancellationToken = default)
    {
        if (messages?.Any() ?? false)
        {
            await context.SendMessageAsync(messages, cancellationToken).ConfigureAwait(false);
        } 

        if (additionalMessages?.Any() ?? false)
        { 
            await context.SendMessageAsync(additionalMessages, cancellationToken).ConfigureAwait(false);
        }
    }
}

3.2 OutputMessagesExecutor

由于用来输出ChatMessage列表的OutputMessagesExecutor时一个internal类型,所以我们不得不重新定义,完整的代码如下所示:

internal sealed class OutputMessagesExecutor : ChatProtocolExecutor, IResettableExecutor
{
    public OutputMessagesExecutor(ChatProtocolExecutorOptions? options = null)
        : base("OutputMessages", options, declareCrossRunShareable: true)
    { }
    protected override ProtocolBuilder ConfigureProtocol(ProtocolBuilder protocolBuilder)
        => base.ConfigureProtocol(protocolBuilder).YieldsOutput<List<ChatMessage>>();

    protected override ValueTask TakeTurnAsync(
        List<ChatMessage> messages,
        IWorkflowContext context,
        bool? emitEvents,
        CancellationToken cancellationToken = default)
    => context.YieldOutputAsync(messages, cancellationToken);
}

3.3 BuildSequential方法

如下所示的是我们自定义的BuildSequential方法的完整代码。我们在调用此方法的时候需要指定一组(AIAgent Agent, List<ChatMessage>? Messages)元组列表。我们利用提供的AIAgent和随后注入的消息列表分别创建出对应的AgentHostExecutor和MessageInjectingExecutor,并将它们按照顺序连接起来。最后我们在Workflow的末尾添加一个OutputMessagesExecutor来输出最终的消息列表。

static Workflow BuildSequential(params (AIAgent Agent, List<ChatMessage>? Messages)[] agentsWithInjectedMessages)
{
    var options = new AIAgentHostOptions
    {
        ReassignOtherAgentsAsUsers = true,
        ForwardIncomingMessages = true
    };

    List<ExecutorBinding> agentExecutors = agentsWithInjectedMessages
        .Select(agent => agent.Agent.BindAsExecutor(options))
        .ToList();
    List<ExecutorBinding> messageInjectingExcutors = agentsWithInjectedMessages
        .Select(agent => (ExecutorBinding)new MessageInjectingExecutor( agent.Messages))
        .ToList();
    
    WorkflowBuilder workflowBuilder = new WorkflowBuilder(agentExecutors[0]);
    for (var index = 0; index < agentExecutors.Count; index++)
    {
        workflowBuilder.AddEdge(agentExecutors[index], messageInjectingExcutors[index]);
        if (index < agentExecutors.Count - 1)
        {
            workflowBuilder.AddEdge(messageInjectingExcutors[index], agentExecutors[index + 1]);
        }        
    }
   
    var outputMessagesExecutor = new OutputMessagesExecutor();
    workflowBuilder
        .AddEdge(messageInjectingExcutors.Last(), outputMessagesExecutor)
        .WithOutputFrom(outputMessagesExecutor);

    return workflowBuilder.Build();
}
内容概要:本文详细记录了对一个Android ARM64静态ELF文件中字符串加密机制的逆向分析过程。该ELF文件的所有字符串均被加密,无法通过常规strings命令或IDA直接识别。作者通过分析发现,加密字符串存储在.rodata段,其解密所需信息(包括密文地址、长度和16位密钥)保存在.data.rel.ro段的40字节描述符中。核心解密函数sub_10F408采用自反的双pass流密码算法,结合固定密钥KEY_TERM(由.data段24字节数据计算得出),实现字节级非线性、位置与长度相关的加密。文章还复现了完整的Python解密脚本,并揭示了该保护机制的本质为代码混淆而非强加密,最终成功批量解密全部956条字符串,暴露程序真实行为,如shell命令模板、设备标识篡改、网络重置等操作。此外,文中还提及未启用的自定义壳框架及其反dump设计。; 适合人群:具备逆向工程基础的安全研究人员、二进制分析人员及对ELF保护技术感兴趣的开发者。; 使用场景及目标:①学习ELF二进制中字符串加密的典型实现方式与逆向突破口;②掌握从结构识别、函数追踪到算法还原的完整逆向流程;③理解“绑定二进制”的完整性校验设计及其局限性;④实践编写IDAPython脚本自动化提取与解密敏感数据。; 阅读建议:此资源以实战案例驱动,不仅展示技术细节,更强调逆向思维与验证方法,建议读者结合IDA调试环境,逐步跟随文中步骤进行动态分析与算法验证,深入理解每一步的推理依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值