第53章 高级反调试技术

本文最后更新于:2022年5月27日 下午

本章将与各位一起学习高级反调试技术(Advanced Anti-Debugging ),这些技术大量应用于各种著名的程序保护器。下面调试示例程序来了解各种高级反调试技术,相信各位的水平会得到很大提高。

53.1 高级反调试技术

PE保护器中使用的高级反调试技术有一些共同特征,如技术难度较高等,令代码逆向分析人员身心俱疲。

应用了这些高级反调试技术的程序包含大量垃圾代码、条件分支语句、循环语句、加密/解密代码以及“深不见底”的调用树(Call-Tree),代码逆向分析人员一旦陷人其中便会迷失方向,根本无法访问到实际要分析的代码,只是在无关紧要的地方徘徊。这些混乱加上代码中动态反调试技术的干扰,使代码逆向分析人员处于束手无策的尴尬境地。

当然,这并不是说调试全无可能,只是说调试的难度大大增加了。对于一名经验丰富的代码逆向分析人员而言,分析PE保护器也是一个非常棘手的问题,需要花费大量的时间与精力。而且, “完美分析”本身就是极其艰巨的任务。

本章将向各位介绍几种典型的高级反调试技术,激起大家的学习兴趣,从而帮助各位进一步提高自身的调试水平。

53.2 垃圾代码

向程序添加大量无意义的代码来增加代码调试的难度,这就是“垃圾代码”反调试技术。尤其是,这些垃圾代码中还含有真正有用的代码或者应用其他反调试技术时,调试程序会变得更加困难。

图53-1显示的是垃圾代码(Garbage code )示例之一。 图53-1所示的代码中,一些指令(PUSH/POP、XCHG、MOV)拥有相同的操作数,最终执行的是一些毫无意义的运算(命令执行后没有什么变化)。 图53-2的示例二的垃圾代码利用SUB与ADD指令为EBX设置值,最后执行4041A0地址处的JMP EBX指令。除此之外,其余指令全部都是垃圾代码,原本用1条JMP XXXXXXXX指令即可实现操作,结果却用了很长、很复杂的代码来实现。

以上示例代码非常简单,调试过程中很容易跳过它们。但是实际的垃圾代码往往具有精巧又复杂的形态,含有大量条件分支语句和无尽的函数调用,想要跳过它们并非易事。

53.3扰乱代码对齐

熟悉了IA-32指令后,巧妙编写汇编代码即可干扰调试器的反汇编结果,反汇编代码看上去会乱作一团,如图53-3所示。

从图53-3的代码可以看岀,41510F地址处的JMP指令用来跳转到415117地址处,但是415117地址处的反汇编代码却未能正常显示。这是由于扰乱代码对齐(Breaking Code Alignment)使OllyDbg调试器生成了错误的反汇编代码。

415115地址处的指令中,操作码为“A3”,对应于MOV指令,用来处理4个字节大小的立即数值。所以该地址处的指令长度最终被解析为5个字节,这正是扰乱代码对齐的花招。415115地址处的“A368” 指令是故意添加的代码,用来扰乱反汇编代码,程序中未使用它,实际的代码仅为415117地址处的 “7201”。

关于IA-32指令解析的内容请参考第49章。

借助StepInto命令进入415117地址,显示正常代码,如图53-4所示。

415117地址处的JB指令也应用了相同技法,打乱了代码对齐。这种“向代码插入(经过精巧设计的)不必要的代码来降低反汇编代码可读性”的技术称为扰乱代码对齐。

尚未完全掌握代码就贸然使用StepOver(F8)等命令追踪调试,很有可能遭遇其他反调试技术拦截。总之,扰乱代码对齐技术是最令代码逆向分析人员苦恼的技术之一。

大部分调试器都拥有IA-32指令智能解析功能,用来生成反汇编代码。OllyDbg调试器也有类似的分析(Analysis)功能,用来提高反汇编代码的可读性。在图53-3中 按Ctrl+A快捷键,弹出图53-5所示的警告窗口(初次调试程序时,若有异常,也会弹出该警告窗口)。

如图53-6所示,OllyDbg调试器无法正常解析指令,反汇编代码解析(Analysis ) 从415115地址开始就失败了。这是因为解析结果中415115~415116地址间的指令(“A368”)被认为语义不正确。

单击“是(Y)“,显示图53-6所示的代码。

从代码流看,程序执行要跳转到415117地址处,但是415112地址与415117地址间的A368指令未能解析为正常的IA-32指令(2字节大小)(A3是总长度为5字节的指令,但根据前后代码看,它仅有2个字节)。此时关闭OllyDbg调试器的解析功能反而会更好。单击鼠标右键,在弹出菜单中依次选择Analysis-Remove analysis frommodule,如图53-7所示。

这样,OllyDbg调试器就不会对代码进行智能解析,而是直接显示原先的反汇编代码,如图53-3所示。

接下来,使用带有强大反汇编功能的IDAPro来分析相同代码,如图53-8所示。

可以看到出现了相同的现象。去往实际地址前,程序代码在OllyDbg与IDA Pro 中都处在代码非对齐状态。

我们通常把纠缠混合在一起的代码称为“混乱代码”(Obfuscated Code ),它们会增加阅读分析代码的难度。灵活运用垃圾代码与扰乱代码对齐技术能够产生非常棒的“混乱代码”。

53.4加密/解密

加密/解密(Encryption/Decryption )是压缩器与保护器中经常使用的技术,用来隐藏程序代码与数据,从而有效防止调试分析程序。

计算机领域中将“为正常代码加密”的行为称为“编码”(Encoding),而把“解 密代码”的行为称为“解码”(Decoding)。

53.4.1简单的解码示例

下面看个简单的解码示例

1
2
3
4
5
6
7
8
9
0040B000 MOV ECX,100
0040B005 MOV ESI,0040B010
0040B00A XOR BYTE PTR DS:[ESI],7F
0040B00D INC ESI
0040B00E LOOPD SHORT 0040B00A
0040B010 POP DS
0040B011 XCHG EAX,EDI
0040B012 JG SHORT 0040B093
0040B014 JG SHORT 0040B095

40B00040B00E地址间的代码是解码循环,用来对40B01040B110地址区域进行解码(XOR 7F )。40B010地址以后的代码只有经过解码才能正常显示。

反转储技术中,加密代码被解码为正常代码后,有时会被再次加密。转储运行中的进程内存代码时,得到的代码仍然处于加密状态。

53.4.2 复杂的解码示例

下面看个更复杂的解码循环,其内部包含大量垃圾代码,如代码53-2所示。

**005910D1 CALL 005910E2 ;()

005910D6 HLT

005910D7 SBB EAX,19606392

005910DC FIDIVR WORD PTR DS:[EDI+DBEAD58C]

005910E2 JNB 005910ED

005910E8 ADC DX,0A953

005910ED POP EBX ; EBX = 5910D6

005910F3 JNB 0059110B

005910F9 JMP 0059110B

0059110B POP ESI

0059110C ADD EBX,0A42 ; EBX = 591B18

00591112 PUSH 7FFFAA31

00591117 MOV EDI,7944ECA2

0059111C POP ESI

0059111D MOV EAX,252 ; EAX = 252 (loop count)

00591122 JMP 00591138

00591138 MOV ECX,DWORD PTR DS:[EBX]

0059113A MOV EDI,22AC5676

0059113F SUB ECX,425C7573

00591145 MOV ESI,EDI

00591147 ADD ECX,77193C30

0059114D PUSH EDI

0059114E CALL 00591164

00591164 MOV ESI,4B1DFA57

00591169 POP EDI

0059116A POP EDI

0059116B SUB ECX,233570A9

00591171 PUSH ESI

00591172 JG 0059117D

00591178 MOV EDI,0A7E8B74

0059117D POP EDI

0059117E MOV DWORD PTR DS:[EBX],ECX

00591180 PUSH EBX

00591181 MOV DX,CX

00591184 POP EDX

00591185 SUB EBX,4E777037

0059118B JMP 00591197

00591190 RCL DWORD PTR DS:[EAX],CL

00591192 OR DWORD PTR DS:[ESI],ECX

00591194 DAS

00591195 CMP AL,0C5

00591197 ADD EBX,4E777033

0059119D MOV DH,8B

0059119F SUB EAX,1

005911A2 JNZ 005911C3

005911A8 SUB DX,421F

005911AD JMP 005911D4 ; 解码结束后跳到解密后的代码

005911B2 XOR EAX,B1583BCA

005911B7 XCHG EAX,ESI

005911B8 POP SS

005911B9 ADD AL,0ED

005911BB AND DH,BYTE PTR DS:[EBX+F6EE970]

005911C1 PUSHFD

005911C2 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESIJ

005911C3 JMP 00591138 ; 继续解码

以上代码中,有效指令与垃圾指令混在一起,看上去比较复杂。但跟踪调试可以发现,上述代码就是解码循环,并且我们能够从中找出有效指令(以上代码用黑粗体表示有效指令)。其中最核心的指令如下所示:

1
2
3
4
5
00591138	MOV ECX,DWORD PTR DS:[EBX]
0059113F SUB ECX,425C7573 ;;;;;;;;;;;;;;;;;;;;
00591147 ADD ECX,77193C30 ;"ADD ECX,11875614";
0059116B SUB ECX,233570A9 ;;;;;;;;;;;;;;;;;;;;
0059117E MOV DWORD PTR DS:[EBX],ECX

上述代码中,先从EBX寄存器所指地址中读取DWORD(4个字节)值,然后与0x11875614相加,再写入原地址。也就是说,在原值基础上加了0x11875614。

EAX寄存器用来为解码循环计数,它先被59111D地址处的MOV指令初始化为0x252,然后被59119F地址处的SUB指令减去1。要解密区域的地址存储在EBX寄存器中,在005910D1、005910ED、0059110C地址处指令的作用下,EBX寄存器的初始值被设置为591B18,然后在以下2条指令的作用下减去4 (EBX的范围为5911D4~591B18)。

1
2
00591185	SUB EBX,4E777037
00591197 ADD EBX,4E777033

最后,所有解码完成后,执行5911AD地址处的JMP指令,跳转到5911D4地址处(解密代码的起始位置)。

1
O05911AD	JMP 005911D4

从代码53-2中删除垃圾指令后,对代码简单整理如下:

005910D1 MOV EAX,252

005910D6 MOV EBX,00591B18

005910DB MOV ECX,DWORD PTR DS:[EBX]

005910DD ADD ECX,11875614

005910E3 MOV DWORD PTR DS:[EBX],ECX

005910E5 SUB EBX,4

005910E8 DEC EAX

005910E9 JNZ SHORT 005910DB

005910EB JMP 005911D4

53.4.3 特殊情况:代码重组

有些程序保护器为了降低代码可读性,增加代码跟踪难度,采用了实时组合执行代码的技术手法。

图53-9中,4150E3地址处的SUB指令与4150E9地址处的DEC指令用来修改其下的代码(分别为4150EF、4150EC)。执行这2条指令后,其下的代码变形如图53-10所示。

可以看到,重新生成了4150EC地址处的指令,CPU会执行新的指令代码。

该技术的另一个优点是,用户在解码的代码处设置软件断点(0xCC)后,程序运行就会引发运行时错误。这是因为,设有断点的区域被0xCC取代,从而出现完全不同的计算结果(OllyDbg 调试器中,为了保护设有软件断点的地址中的数据,干脆禁止写入新值)。

以上代码为PESpin保护器(PESpin(1.32).exe)的EP代码

53.5 Stolen Bytes (Remove OEP)

Stolen Bytes(或者Remove OEP)技术将部分源代码(主要是OEP代码)转移到压缩器/保护器创建的内存区域运行。

该技术的优点是,转储进程内存时,一部分OEP代码会被删除,转储的文件无法正常运行反转储技术。另一优点是,应用Stolen Bytes技术的文件再次经过压缩器/保护器压缩后,会给逆向分析人员造成很大混乱。文件脱壳后,得到的不是熟悉的OEP代码,而是其他形态的代码,这很难判断是脱壳成功还是需要继续操作,容易引起代码逆向分析人员的混乱(我们常用“迷路、徘徊”等词汇描述这种状态)。为帮助各位理解该技术,下面分析练习示例(stolen_bytes.exe)。首先在OllyDbg调试器中打开示例程序,进入程序的EP代码,如图53-11所示。

示例程序(stolen_bytes.exe)是用Microsoft Visual C++ 6.0工具编译的可执行文件,图53-11为其EP代码(使用Visual C++ 2008/2010编译的可执行文件的EP代码形态与此不同)。在PESpin保护器中开启“RemoveOEP”选项,打开示例程序文件,执行“Protect”(保护文

件)操作(stolen_bytes_pespin.exe)。在OllyDbg调试器中打开stolen_bytes_pespin.exe程序文件,转到OEP附近的地址处(参考图53-12)。

使用作者提供的二进制文件,发现是一些垃圾代码,并没有被替换成NULL。

从图53-12可以看到,401088地址之前的代码都被替换为NULL值(请与前图中的EP代码比较)。虽然图53-12并未显示全部代码,但可以看到OEP(401041)~401087区域中的代码已被删除。删除的代码被保存到PESpin添加的节区,脱壳后调用执行。以下代码就是保存在PESpin节区中的“消失的OEP代码”。

从以上代码可以看岀,OEP代码采用了扰乱代码对齐技术拆分保存。最终执行40CD76地址处的JMP指令,将程序执行跳转到源代码节区(401088)。

不同类型保护器的处理方式不同,有些保护器会先保存Stolen Bytes再运行,而有些保护器运行完Stolen Bytes后会将它们直接从内存中删除(分配内存-解密Stolen Bytes代码-运行-释放内存)。

53.6 API 重定向

在主要的Win32 API(文件、注册表、进程、网络等)处设置断点,就能在调试程序时快速掌握代码流。

图53-13是OllyDbg调试器的断点窗口,列岀了主要API起始代码中设置的断点。在该状态下运行(RUN(F9))被调试进程,每当调用以上断点列表中的API时,程序暂停执行,返回地址被存储到栈(参考图53-14)。接下来,只要从返回地址继续调试就可以了。要调试的代码非常多时,采用该方法非常高效,且能轻松进入核心代码调试。

API重定向就是破解上面这种调试手法的技术。程序保护器通常会先将全部(或部分)主要的API代码复制到其他内存区域,然后分析要保护的目标进程代码,修改调用API的代码,从而使自身复制的API代码得以执行。这样,即使在原API地址处设置断点也没用(此外,该技术还支持反转储功能)。

下面分析一段应用API重定向技术的代码,帮助各位加深理解。

53.6.1 原代码

首先在OllyDbg调试器中打开示例程序(api_redirection_org.exe),原代码如图53-15所示。

4010B5地址处的CALL DWORD PTR DS:[406000]指令中,地址406000即为IAT区域,其中含有kernel32!GetCommandLineA()API地址(7C812FAD)。kernel32!GetCommandLineA()API的实际代码如图53-16所示。

可以看到其代码非常简单,仅返回7C8855F4地址(kernel32.dll的.data区域)中存储的值。严格地说,DWORD PTR DS:[7C8855F4]为kernel32.dll的全局变量。

53.6.2 API重定向示例#1

下面分析api_redirection1.exe示例程序,它在上面原代码的基础上应用了API重定向技术。

与原代码(图53-15湘比,IAT地址由原来的406000变为40FE1F,且40FE1F地址的值为3F0000(原代码中该地址为kernel32.dll内API的地址)。

api_redirection1.exe文件是使用PESpin保护器的API重定向选项制作的。使用调试器进行运行时解压缩后,运行到OEP处就会出现上图中的(变形后的)原代码。解压缩后也应用API重定向技术。

地址3F0000是保护器分配的内存区域的起始地址,保护器将主要的API代码复制到该地址区域。在图53-17中跟踪(StepInto(F7))位于4010B5地址处的CALL指令,查看3F0000地址处的代码。

从图53-18可以看到,代码中应用了扰乱代码对齐技术,跟踪JMP指令可以看到实际的API代码。

图53-19中的代码与实际的kernel32!GetCommandLineA()API代码(参考图53-16)完全相同。保护器将原API代码复制到该处。

保护器会像这样重新组织原程序的IAT,并全部修改调用相关API的代码。最终调用的不是Kernel32模块中的原API,而是3F0000地址区域中的API。

53.6.3 API重定向示例#2

下面看个更复杂的API重定向示例,该示例程序(api_redirection2.exe)是使用ASProtect的

Advanced Import Protection与Emulate standard system function功能制作的,如图53-20所示。

在原程序与本示例中比较4010B5地址处的CALL指令(参考图53-15)。

虽然2条CALL指令相同,但操作码却不同。操作码“FF15” 表示间接调用7C812FAD地址(该

地址存储在406000地址中)处的函数。操作码“E8” 表示直接调用(指定地址值(76EF46)加 上Next EIP(401 OBA)得到的)新地址(76EF46+4010BA=B70000)中的代码。

原来的6字节CALL指令(FF15 00604000)被改为5字节CALL指令(E8

46EF7600), 4010BA地址处仅剩下B8,这意味着代码中会出现代码对齐混乱效果(运 行B70000函数代码,返回地址被修改为与原代码相同的地址4010BB)。

B70000地址区域是ASProtect在脱壳过程中分配的众多内存区域之一(参考图53-21)。

跟踪进入(StepInto(F7))B70000函数,代码如图53-22所示。

从图中可以看到,代码中含有垃圾代码,也应用了扰乱代码对齐技术。实际的

GetCommandLineA()API代码要一段时间后才显示。

每次使用调试器转到B70000地址时,代码形态均不同。因为ASProtect的混淆代

码生成器每次都会生成新的垃圾代码。我们把这种能产生相同结果而又具有不同形态

的代码称为多态代码(Polymorphic Code)。前面还介绍过一种“混乱代码”(Obfuscated

Code),今后会经常用到它们,希望各位借此机会记住。图53-22中的代码同时具有“多

态代码”和“混乱代码”的特征(代码形态随时变化,我们很难把握)。

B70000地址处的代码是ASProtect添加的垃圾代码,用来设置调试障碍,增加调试难度。在

OllyDbg调试器中跟踪调试时,要运行约3万条指令(包含循环中反复调用的指令),然后返回原

代码中的4010BB地址处(参考图53-23)。

也就是说,原代码中的1条CALL DWORD PTR DS:[406000]指令被换成了3万条指令(除

Kernel32!GetCommandLineA()API夕卜,其他很多API也采用这种调用方式)。该方式执行效率非常

低,但是对保护代码与增加代码逆向分析难度来说,效果非常棒。

垃圾代码中包含实际调用API的代码,如图53-24所示。

与前面介绍的PESpin示例程序(api_redirectionl.exe)不同,该示例程序会直接调用头际

的kernel32!GetCommandLineA()API,并修改返回地址(4010BA—4010BB),代码如图53-25

所示。

通过跟踪图53-20中4010B5地址处的CALL B70000指令调试到此,图53-25中[EAX]=

[12FF3C]=4010BA即是调用B70000函数后的返回地址。若直接返回4010BA地址就会引发错误,

所以,借助455E9D地址处的MOV指令将返回地址修改为4010BB,如图53-26所示。

图53-25的地址区域(455E9D)是ASProtect的代码节区区域(参考图53-21)。与 B70000区域一样,它不是为了生成垃圾代码而分配的内存区域,而是实实在在的

ASProtect的代码节区区域。

最后返回原代码的4010BB地址处,代码如图53-26所示

图53-26中的代码(B800B3)也是ASProtect创建的多态&混乱代码,每次调试都会变化。

我们至此学习了具有复杂形态的API重定向示例,API重定向这种方式牺牲了代码的运行速

度,却大大提高了代码的复杂性,从而获得了很好的反调试效果。

若代码逆向分析人员事先并不知道程序中调用了哪些API(或者要花很长时间才能查明),就

会使代码逆向分析工作变得十分困难。因此,API重定向是一种相当有效的反调试技术,许多程

序保护器都支持它。

参考上面学过的内容,请各位亲自跟踪调试B70000处的函数。我借助OllyDbg的 “硬件断点”功能,获取了图53-25、图53-26中出现的455E9D与B800B3地址。进 入B70000函数后,返回地址存储在栈中,在ESP值(我在12FF3C地址处设置硬件断

点后获取了 455E9D地址)与4010BB地址处设置断点跟踪,就会见到B800B3地址处

的JMP指令。

API重定向技术在结构上与API钩取技术有很多类似的地方:它们都不直接调用原API,而是

添加自身代码并执行后再调用。二者最大的不同在于,它们的目的是不一样的:APJ重定向用来

增加代码调试的难度,而API钩取则用来在API调用前/后添加另外的功能。

53.7 Debug Blocker(Self Debugging)

Debug Blocker(Self Debugging)也是一种高级反调试技术,顾名思义,它在调试模式下运行自身进程。

图53-27中的PESpin(1.32).exe进程为PESpin保护器。可以看到,同一进程以父进程(PID: 184) / 子进程(PID: 1424)形式运行。其实,它们是调试器(PID: 184)与被调试者(PID: 1424)的关系。PESpin运行后会查找自身的可执行文件,然后以调试模式执行。

Debug Blocker是自我创建技术(以子进程形式运行自身进程)的演进形式。自我创建技术中,子进程负责执行实际原代码,父进程负责创建子进程、修改内存(代码/数据)、更改EP地址等。所以仅调试父进程将无法转到OEP代码处,这样能起到很好的反调试效果。但调试时若用附加命令将子进程附加到调试器,这种反调试手法就会失去作用。Debug Blocker技术的出现正是为了弥补这一不足。

Debug Blocker技术有如下优点。

第一,防止代码调试。因子进程运行实际的原代码且已处于调试之中,原则上就无法再使用其他调试器进行附加操作了(第57章中将介绍一种方法,它可以解决该问题并顺利实现调试)。

第二,能够控制子进程(Debuggee,被调试者)。调试器-被调试者关系中,调试器具有很大权限,可以处理被调试进程的异常、控制代码执行流程等。

Debug Blocker技术的第二个优点使代码调试变得非常困难。下面比较常规反调试技术与Debug Blocker技术。

图53-28左侧为应用常规SEH技术的反调试示例,右侧为应用Debug Blocker技术的反调试示例。常规SEH技术中,异常处理器代码位于相同的进程内存空间;但Debug Blocker技术中,(处理被调试进程所发异常的)异常处理器代码位于调试进程(请注意,对于被调试进程所发的异常,调试器拥有优先处理权)。

所以,为了调试子进程,必须先断开与已有调试器的连接,但这样子进程又无法正常运行。这正是逆向分析Debug Blocker最难的部分。

第57章中将调试应用了Debug Blocker的示例程序,帮助各位进一步了解

Nanomite技术由Debug Blocker技术发展而来,该技术会查找被调试进程内部的代码,将所有条件跳转指令(Jcc指令)修改为INT3(0xCC)指令(软件断点),或其他触发异常的代码。并且,调试器内部有表格,含有被修改的Jcc指令的实际地址位置以及要跳转的地址。执行被调试者内部修改后的指令就会触发异常,控制权即被转交给调试器。调试器通过发生异常的地址从(自身持有的)表格中获取要跳转的地址,然后通知被调试者。图53-29是含有条件跳转指令的原代码。

使用PESpin保护器向前面的原代码应用Nanomite技术,出现如图53-30所示的代码。

认真比较可以发现,2个字节的Jcc/MOV指令全部被修改为LEA EAX,EAX这类怪异的指令。执行这种代码时就会触发EXCEPTION_ILLEGAL_INSTURCTION异常,系统会将控制权转移给调试器。

若想正常调试这种应用了Nanomite技术的代码,需要把修改后的代码恢复为原代码。逐一手动修改会非常费力,大量恢复工作要实现自动化处理,这需要我们具备一定的编程思维与能力。所以,调试这种应用了Nanomite技术的代码是很有难度的。

53.8 小结

本章讲解了PE保护器中常用的高级反调试技术的相关内容(随着反调试技术的不断发展,各种技术会应运而生)。

我刚开始学习代码逆向分析技术时,曾经尝试调试ASProtector。连续分析了好几天,但是连OEP代码的边都没摸到,总是在奇怪的地方徘徊。这是因为受到了反调试代码的阻碍,这些代码常被称为“死亡代码”。若想顺利通过数量庞大的代码,必须坚信自己最后一定能够找到OEP代码。其实,陷入“死亡代码”的沼泽是绝对不可能找到OEP代码的。调试时会不断出现混乱代码,让人疲惫不堪。我当时跟踪调试这些代码时也深受其苦,最后竟然不知不觉间打起了瞌睡,那时才真正体会到反调试技术的可怕。这些反调试技术从精神与肉体上折磨逆向分析人员,打消他们调试代码的念头。两年后,我再次挑战ASProtector,学习从网络上获取的各种反调试相关资料,最终顺利达到OEP处,当时真是高兴坏了。

但那也只是回避了反调试技术而到达OEP处而已,其实仍未能完全掌握ASProtector的工作原理(内部算法)。我当时再次感受到自身的不足,觉得要学的东西还很多,一定要虚心学习。另一方面也认为编写该PE保护器的人实在太有水平了。各位的逆向分析技术达到一定水平后,我建议大家调试一下PE保护器。查找、学习相关资料,在调试过程中认真分析,相信各位会学到大量知识并积累丰富经验,进一步提高代码调试水平。


第53章 高级反调试技术
https://m0ck1ng-b1rd.github.io/1999/05/03/逆向工程核心原理/第53章 高级反调试技术/
作者
何语灵
发布于
1999年5月3日
许可协议