010220AC 90 NOP
010220AD 90 NOP
010220AE 8BB5 F6DE4000 MOV ESI,DWORD PTR SS:[EBP+40DEF6]
010220B4 53 PUSH EBX
010220B5 50 PUSH EAX
010220B6 E8 CABCFFFF CALL NOTEPAD_.0101DD85
010220BB 8BD8 MOV EBX,EAX
010220BD 58 POP EAX
010220BE 33C3 XOR EAX,EBX
010220C0 C606 68 MOV BYTE PTR DS:[ESI],68
010220C3 8946 01 MOV DWORD PTR DS:[ESI+1],EAX
010220C6 C746 05 81342400 MOV DWORD PTR DS:[ESI+5],243481
010220CD 895E 08 MOV DWORD PTR DS:[ESI+8],EBX
010220D0 C646 0C C3 MOV BYTE PTR DS:[ESI+C],0C3
010220D4 5B POP EBX
010220D5 8BC6 MOV EAX,ESI
010220D7 8385 F6DE4000 0D ADD DWORD PTR SS:[EBP+40DEF6],0D
010220DE 5E POP ESI
010220DF 8907 MOV DWORD PTR DS:[EDI],EAX ;③ 这里把API写入正确的IAT里
010220E1 8385 2DDE4000 04 ADD DWORD PTR SS:[EBP+40DE2D],4 ;d EDI 就可以看到程序原本的
010220E8 ^ E9 C6FEFFFF JMP NOTEPAD_.01021FB3 ;IAT跳转表
010220ED 83C6 14 ADD ESI,14
010220F0 8B95 31DE4000 MOV EDX,DWORD PTR SS:[EBP+40DE31]
010220F6 ^ E9 28FEFFFF JMP NOTEPAD_.01021F23
010220FB 60 PUSHAD \;④ 上面的①②改掉后,用F4直接运行到这里
010220FC E8 00000000 CALL NOTEPAD_.01022101 |;也可下硬件断点,F9运行,断下后
01022101 5E POP ESI |;再把①②处改会原来的代码.
01022102 83EE 06 SUB ESI,6 |;一定要改回去,不然壳会在最后
01022105 B9 09020000 MOV ECX,209 |;效验并解密伪OEP处代码时出错!
0102210A 29CE SUB ESI,ECX |
0102210C BA BAA8FF62 MOV EDX,62FFA8BA |
01022111 C1E9 02 SHR ECX,2 |
01022114 83E9 02 SUB ECX,2 |
01022117 83F9 00 CMP ECX,0 |
0102211A 7C 1A JL SHORT NOTEPAD_.01022136 |
0102211C 8B048E MOV EAX,DWORD PTR DS:[ESI+ECX*4] |
0102211F 8B5C8E 04 MOV EBX,DWORD PTR DS:[ESI+ECX*4+4] |
01022123 2BC3 SUB EAX,EBX |
01022125 C1C8 1F ROR EAX,1F |
01022128 33C2 XOR EAX,EDX |
0102212A 81C2 D82567EC ADD EDX,EC6725D8 |
01022130 89048E MOV DWORD PTR DS:[ESI+ECX*4],EAX |
01022133 49 DEC ECX |
01022134 ^ EB E1 JMP SHORT NOTEPAD_.01022117 /;这段循环是把010220F6前的代码
01022136 61 POPAD ;恢复加密,这样的循环在Acpr里
01022137 61 POPAD ;随处可见,每段解密后的执行代码后
01022138 C3 RETN ;都会有这样的恢复加密的循环
PS:在③处d edi后,可以在内存窗口里随便找一个字节,把它随便改成别的值,然后再改会原来的值,这样OD就会把之后写入该内存页所有的值用红色高亮显示,在④处断下后,在内存窗口里找到最前面的用红色显示的值,它的地址就是IAT了!我这里看到的是01001000,用ImportREC得到输入表时RAV里填的就是01001000-01000000=1000
———————————————————————————————————
3.快速到达处理Stolen code的地方
我们已经在01010F19下了硬件访问断点,在做完上面的处理后,按F9运行,就会直接断在开始处理Stolen code的地方,如下
.
.
.
.
010236D1 61 POPAD
010236D2 56 PUSH ESI
010236D3 BE E50E0101 MOV ESI,NOTEPAD_.01010EE5
010236D8 890E MOV DWORD PTR DS:[ESI],ECX
010236DA 5E POP ESI
010236DB FF35 E50E0101 PUSH DWORD PTR DS:[1010EE5]
010236E1 893C24 MOV DWORD PTR SS:[ESP],EDI
010236E4 57 PUSH EDI
010236E5 BF 190F0101 MOV EDI,NOTEPAD_.01010F19
010236EA 893D E10E0101 MOV DWORD PTR DS:[1010EE1],EDI
010236F0 5F POP EDI
010236F1 FF35 E10E0101 PUSH DWORD PTR DS:[1010EE1] ; NOTEPAD_.01010F19
010236F7 8B3C24 MOV EDI,DWORD PTR SS:[ESP]
010236FA 8F05 DD0E0101 POP DWORD PTR DS:[1010EDD] ; NOTEPAD_.01010F19
01023700 892F MOV DWORD PTR DS:[EDI],EBP ;EDI=01010F19
01023702 8B3C24 MOV EDI,DWORD PTR SS:[ESP] ;断在这儿
01023705 8F05 F90E0101 POP DWORD PTR DS:[1010EF9]
0102370B FF35 190F0101 PUSH DWORD PTR DS:[1010F19]
01023711 8925 150F0101 MOV DWORD PTR DS:[1010F15],ESP
01023717 893D BD0E0101 MOV DWORD PTR DS:[1010EBD],EDI
0102371D 90 NOP
0102371E 90 NOP
0102371F 60 PUSHAD
01023720 50 PUSH EAX
01023721 E8 01000000 CALL NOTEPAD_.01023727
.
.
.
.
从这段代码起Acpr开始处理Stolen code,具体的Stolen code我不是很在行,几位老大已经分析的清晰透彻了.
Acpr对Stolen code处理的代码是分段解密后再执行的,因为我们前面在这个内存页里改过数据,所以所有重新写入的代码都是用红色高亮显示了,这就给我们用F4快速执行过解密代码带来了方便,具体方法是在最后一句高亮显示的代码开始向上找0F85 xxFFFFFF(JNZ xxxxxxxx)远程跳转语句,然后F4到它下面的一句上,有的0F85 xxFFFFFF的语句会因为它前后的代码环境而不被OD显示出来,这是可以Crtl+G到0F85 xxFFFFFF的地址,也可以找到高亮显示的最后一个E8 010000 或EB 01,然后F4到其上,再F7几步就可以看到0F85 xxFFFFFF(JNZ xxxxxxxx)了
处理Stolen code的前几段代码都是对堆栈的处理,要是不分析Stolen code的话可以不用管,但是后面几段因为会包含到程序OEP的Call,如果执行这些Call的话,就有可能因为执行了Replace Code而改变程序的数据结构.
我的处理方法是把这些Call先nop掉,在执行完nop后,在把Call的代码恢复回去,例如:下面代码执行到①处CALL DWORD PTR DS:[100115C] 时把它先用nop填充掉,等走完nop后再把CALL DWORD PTR DS:[100115C]写回去,但②③会用到EAX指针,我们跳过了Call,所以到②和③时会出错,于是一不做二不休,把②③的代码也按刚才的方法干掉
01028D7E /E9 04000000 JMP NOTEPAD_.01028D87
01028D83 |66:BD 27CC MOV BP,0CC27
01028D87 \61 POPAD
01028D88 FF15 5C110001 CALL DWORD PTR DS:[100115C] ; msvcrt.__p__fmode ①
01028D8E 891D 110F0101 MOV DWORD PTR DS:[1010F11],EBX
01028D94 FF35 110F0101 PUSH DWORD PTR DS:[1010F11]
01028D9A C705 0D0F0101 4>MOV DWORD PTR DS:[1010F0D],NOTEPAD_.010088>
01028DA4 8B1D 0D0F0101 MOV EBX,DWORD PTR DS:[1010F0D] ; NOTEPAD_.010065D0
01028DAA 8B0B MOV ECX,DWORD PTR DS:[EBX]
01028DAC 8B1C24 MOV EBX,DWORD PTR SS:[ESP]
01028DAF 8F05 090F0101 POP DWORD PTR DS:[1010F09]
01028DB5 8908 MOV DWORD PTR DS:[EAX],ECX ;②
01028DB7 FF15 4C110001 CALL DWORD PTR DS:[100114C] ; msvcrt.__p__commode
01028DBD 53 PUSH EBX
01028DBE 893424 MOV DWORD PTR SS:[ESP],ESI
01028DC1 57 PUSH EDI
01028DC2 BF 40880001 MOV EDI,NOTEPAD_.01008840
01028DC7 8BF7 MOV ESI,EDI
01028DC9 5F POP EDI
01028DCA 8B16 MOV EDX,DWORD PTR DS:[ESI]
01028DCC 8B3424 MOV ESI,DWORD PTR SS:[ESP]
01028DCF 8F05 050F0101 POP DWORD PTR DS:[1010F05]
01028DD5 8910 MOV DWORD PTR DS:[EAX],EDX ;③
01028DD7 90 NOP
01028DD8 60 PUSHAD
01028DD9 E8 01000000 CALL NOTEPAD_.01028DDF
PS:每段处理Stolen code的代码前总要走好几段解密代码,鼠标滚轮费的紧啊,偶的食指也隐隐作痛了 越往后走F4就越要甚用,不然一不小心就会跟飞,不放心的话最好用F7步入,最后来到下面:
01029A80 E8 6245FFFF CALL NOTEPAD_.0101DFE7 ;EBP=00C0F000
01029A85 8DB5 80B04100 LEA ESI,DWORD PTR SS:[EBP+41B080] ;EBP+41B080=102A080,就是前面我们
01029A8B 8DBD 1EE34000 LEA EDI,DWORD PTR SS:[EBP+40E31E] ;记下的GetProcAddress的地址!
01029A91 B9 05000000 MOV ECX,5
01029A96 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
01029A98 40 INC EAX ;这里把包含GetProcAddress在内
01029A99 EB 01 JMP SHORT NOTEPAD_.01029A9C ;的5个API地址Copy到[101D31E]
这5个API是壳的IAT里的,依次是GetProcAddress.GetModuleHandleA.LoadLibraryA.ExitProcess.MessageBoxA
这段之后再经过一段解密代码就到了壳解密伪OEP处代码并跳向伪OEP的地方,所以如果要快速到达伪OEP,就可以在前面我们得到GetProcAddress的地址时,在它上面下硬件访问断点!
