• 标 题:天然码输入法
  • 作 者:leo-cyl  
  • 时 间:2002/01/16 12:50pm 
  • 链 接:http://bbs.pediy.com

目标软件:天然码输入法(对应小球兄昨天的帖子)
目标文件:trm32.ime;getdiskserial.exe
加壳方式:UPX 1.03
使用工具:trw2000
         Procdump
         peditor
         Imprec 1.3
URL:  http://www.chinatrm.com/download/file/suggest/setup.exe
本文作者:leo_cyl

加密特点:在比较注册码前,先产生另外的进程调用vxd绕过window api读指纹盘,如果没有指纹盘就不比较注册码。其实这个软件是明码比较不用脱壳的,但对dll脱壳是很多初学者还没掌握的基本技能,所以还是多此一举把trm32.ime的壳脱了。(trm32.ime说穿了就是一个dll)
dll壳脱的难点在于dll是动态加载的(废话!),所以不能用loader。那么我们只好在dll的entry point加上int 3的指令了。
用peditor装入\windows\system\trm32.ime,可看到entry point = 0003D210;Image Base = 10000000;用peditor的FLC计算entry point(1003d210)的偏移为:00013610。再用二进制编辑器在偏移为00013610处机器码为80H的内容改为CC(即 int 3的机器码)。
现在运行trw2k,下命令“I3HERE ON”,打开任务条的输入法管理器。选天然码,点“属性”将激活trw2k,停在dll的入口处:
017F:1003D210 CC               INT3    
017F:1003D211 7C24             JL       1003D237             (NO JUMP)
017F:1003D213 0801             OR       [ECX],AL
017F:1003D215 0F8581010000     JNZ      NEAR 1003D39C
017F:1003D21B 60               PUSHA  
017F:1003D21C BE00A00210       MOV      ESI,1002A000

“r eip eip-1”,“d eip”,将017F:1003D210处改为80H:
017F:1003D210 807C240801       CMP      BYTE [ESP+08],01
017F:1003D215 0F8581010000     JNZ      NEAR 1003D39C
017F:1003D21B 60               PUSHA  
017F:1003D21C BE00A00210       MOV      ESI,1002A000
017F:1003D221 8DBE0070FDFF     LEA      EDI,[ESI+FFFD7000]
017F:1003D227 57               PUSH     EDI

f10跟踪,来到这里:
017F:1003D344 95               XCHG     EAX,EBP
017F:1003D345 8A07             MOV      AL,[EDI]
017F:1003D347 47               INC      EDI    《===EDI为引入的函数名
017F:1003D348 08C0             OR       AL,AL
017F:1003D34A 74DC             JZ       1003D328
017F:1003D34C 89F9             MOV      ECX,EDI
017F:1003D34E 57               PUSH     EDI
017F:1003D34F 48               DEC      EAX
017F:1003D350 F2AE             REPNE SCASB
017F:1003D352 55               PUSH     EBP
017F:1003D353 FF9634DA0300     CALL     NEAR [ESI+0003DA34] 〈==getprocessaddress
017F:1003D359 09C0             OR       EAX,EAX
017F:1003D35B 7407             JZ       1003D364
017F:1003D35D 8903             MOV      [EBX],EAX
017F:1003D35F 83C304           ADD      EBX,BYTE +04
017F:1003D362 EBE1             JMP      SHORT 1003D345

以上代码为恢复引入表。继续f10跟踪,来到这里:
017F:1003D38C EBE2             JMP      SHORT 1003D370
017F:1003D38E 240F             AND      AL,0F
017F:1003D390 C1E010           SHL      EAX,10
017F:1003D393 668B07           MOV      AX,[EDI]
017F:1003D396 83C702           ADD      EDI,BYTE +02
017F:1003D399 EBE2             JMP      SHORT 1003D37D
017F:1003D39B 61               POPA       〈====很眼熟吧!
017F:1003D39C E906BBFCFF       JMP      10008EA7〈====OEP

所以OEP在10008EA7处。在10008EA7处DUMP出文件。先看一下trm32.ime的IMTE。“MOD32 TRM32.IME”
可看到IMTE 为:xxxxxxxx;“PEDUMP C:\TRM32.DLL xxxxxxxx”。并挂起进程“SUSPEND”。
回到window运行Imprec 1.3。在任务列表选rundll32.exe 点“pick dll”找到trm32.ime。输入OEP(8EA7)
“get Imports”可修复IAT。再“fix dump”。将产生TRM32_.DLL,把它改名为trm32.ime 即可。到此脱壳完成。

用dump出的trm32.ime替换原来的文件。再次运行输入法管理器。选天然码,点“属性”,将弹出MESSAGEBOX说没有指纹盘或disk serial不对。control-n激活trw2k,“pmodule”,“确定”后,回到trw2k:
:00401514 89442410                mov dword ptr [esp+10], eax
:00401518 8B442434                mov eax, dword ptr [esp+34]
:0040151C 50                      push eax
:0040151D E88EFCFFFF              call 004011B0       〈=====进入
:00401522 8BD8                    mov ebx, eax
:00401524 3BDE                    cmp ebx, esi
:00401526 7528                    jne 00401550
:00401528 56                      push esi

* Possible StringData Ref from Data Obj ->"DiskSerial"
                                 |
:00401529 68DC704000              push 004070DC
:0040152E B8847F4000              mov eax, 00407F84

* Possible StringData Ref from Data Obj ->"Disk not exists or process failed "
                                       ->"!"
                                 |
:00401533 68B8704000              push 004070B8
:00401538 56                      push esi
:00401539 89442424                mov dword ptr [esp+24], eax
:0040153D 89442428                mov dword ptr [esp+28], eax
:00401541 89442420                mov dword ptr [esp+20], eax

* Reference To: USER32.MessageBoxA, Ord:01BEh
                                 |
:00401545 FF15C8604000            Call dword ptr [004060C8]
:0040154B E9A1000000              jmp 004015F1

注意这时是在getdiskserial.exe的领空。(也就是说trm32.ime产生getdiskserial.exe进程)。往上看,注意0040151D处的call 004011B0,在此处下断点,再次运行进入“call 004011B0”来到这:
017F:00401439 50               PUSH     EAX
017F:0040143A 8D8C2488030000   LEA      ECX,[ESP+0388]
017F:00401441 6A04             PUSH     BYTE +04
017F:00401443 51               PUSH     ECX
017F:00401444 6A00             PUSH     BYTE +00
017F:00401446 6A00             PUSH     BYTE +00
017F:00401448 6A01             PUSH     BYTE +01
017F:0040144A 56               PUSH     ESI
017F:0040144B FF1514604000     CALL     `KERNEL32!DeviceIoControl` 〈=调用vxd
017F:00401451 56               PUSH     ESI
017F:00401452 FF151C604000     CALL     `KERNEL32!FindCloseChangeNotification`
017F:00401458 8BB42490130000   MOV      ESI,[ESP+1390]
017F:0040145F 8A843484030000   MOV      AL,[ESP+ESI+0384]
017F:00401466 84C0             TEST     AL,AL      〈==是否有指纹盘或disk serial  ?
017F:00401468 744D             JZ       004014B7    〈==没有就跳        
017F:0040146A 8BC6             MOV      EAX,ESI

017F:0040144B处调用diskserial.vxd绝对读磁盘,017F:00401468处是判断。因为没有指纹盘,将此处改为nop;nop;替换getdiskserial.exe(在window的system下)。

再次运行,这次可以来到“属性”窗口,点“确定”可来到注册窗口,我的机器码为123456789012,输入用户名leo_cyl,注册码12121212。下断点hmemcpy,跟踪来到这里:
:10001FC2 8D4C240C                lea ecx, dword ptr [esp+0C]
:10001FC6 8D542414                lea edx, dword ptr [esp+14]
:10001FCA 51                      push ecx
:10001FCB 8D442434                lea eax, dword ptr [esp+34]
:10001FCF 52                      push edx
:10001FD0 50                      push eax
:10001FD1 E85A5E0000              call 10007E30
:10001FD6 83C40C                  add esp, 0000000C
:10001FD9 E822600000              call 10008000     《=====注意
:10001FDE A1ACF90110              mov eax, dword ptr [1001F9AC]
:10001FE3 6A00                    push 00000000
:10001FE5 85C0                    test eax, eax
:10001FE7 7425                    je 1000200E     〈===跳的话就注册失败
:10001FE9 6878F10010              push 1000F178
:10001FEE 686CF10010              push 1000F16C
:10001FF3 56                      push esi

* Reference To: user32.MessageBoxA, Ord:01B7h
                                 |
:10001FF4 FF15A0D10010            Call dword ptr [1000D1A0]
:10001FFA 6A01                    push 00000001
:10001FFC 56                      push esi

* Reference To: user32.EndDialog, Ord:00B9h
                                 |
:10001FFD FF1590D20010            Call dword ptr [1000D290]
:10002003 5F                      pop edi
:10002004 5E                      pop esi
:10002005 33C0                    xor eax, eax
:10002007 5B                      pop ebx
:10002008 83C438                  add esp, 00000038
:1000200B C21000                  ret 0010

进入:10001FD9 处的call 10008000:
。。。。。
。。。。。
:10008038 894C2450                mov dword ptr [esp+50], ecx
:1000803C 89542410                mov dword ptr [esp+10], edx
:10008040 89442420                mov dword ptr [esp+20], eax
:10008044 894C2454                mov dword ptr [esp+54], ecx
:10008048 56                      push esi
:10008049 6689542418              mov word ptr [esp+18], dx
:1000804E 6689442428              mov word ptr [esp+28], ax
:10008053 66894C245C              mov word ptr [esp+5C], cx
:10008058 57                      push edi
:10008059 8854241E                mov byte ptr [esp+1E], dl
:1000805D 8844242E                mov byte ptr [esp+2E], al
:10008061 884C2462                mov byte ptr [esp+62], cl
:10008065 E826A4FFFF              call 10002490      〈======注意此call
:1000806A 8BF8                    mov edi, eax
:1000806C 83C9FF                  or ecx, FFFFFFFF
:1000806F 33C0                    xor eax, eax
:10008071 8D542410                lea edx, dword ptr [esp+10]
:10008075 F2                      repnz
:10008076 AE                      scasb
:10008077 F7D1                    not ecx

10008065 处的call将调用ShellExecuteA的window api 产生getdiskserial.exe进程。假设刚才没改getdiskserial.exe的话,有两个进程要跟踪,比较麻烦,如果非法用户的话getdiskserial将弹出MESSAGEBOX,注册失败。
继续跟踪来到这里:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10008191(C)
|
:1000817D 8A540430                mov dl, byte ptr [esp+eax+30]  〈==这是假注册码
:10008181 8A4C0468                mov cl, byte ptr [esp+eax+68]   〈==正确注册码
:10008185 3AD1                    cmp dl, cl
:10008187 0F851BFFFFFF            jne 100080A8
:1000818D 40                      inc eax
:1000818E 83F809                  cmp eax, 00000009
:10008191 7CEA                    jl 1000817D
:10008193 5F                      pop edi
:10008194 C705ACF9011001000000    mov dword ptr [1001F9AC], 00000001
:1000819E 5E                      pop esi
:1000819F 81C480000000            add esp, 00000080
:100081A5 C3                      ret

“d esp+eax+68”将看到正确注册码:2023252219。
到此pj完成。打了那么多字,好累啊!(随便说一句这个输入法我一点也不喜欢,呵呵……)

  • 标 题:天然码输入法
  • 作 者:hying
  • 时 间:2002/01/18 08:03

我的感觉是DLL的OEP一般比EXE的OEP好找,DLL的入口在程序载入时会执行一次,退出时又会执行一次,所以我看过的DLL的壳大多有一段比较明显的代码大致如下:
cmp  [xxxxxxx],1
jz  ReturnToOEP
……
mov  [xxxxxxx],1
……
ReturnToOEP:
……
jmp  OEP
原理是设置一个标记,第一次需要执行中间的解码过程,退出时当然不需要再次解码,所以直接跳到ReturnToOEP,所以可以bp ReturnToOEP,然后再走几步就可以到OEP了。