软件地址: http://goldsun.ys168.com 对外公布\mjcs_ori_unpack.zip 1.5MB
文章出自:PeaceClub
工具: Ollydbg,kerberos API spy,Imprec,HideOD
情况说明:一个朋友让我检查一下此软件是否有后门,所以就拿来研究了一下.
分析:Peid一看是未知壳,而且是自创进程型的.用ollydbg载入,发现有anti,所以用了看雪的HideOD插件,运行
后主进程ExitProcess退出,CreateProcessA创建的子进程运行中.
POEP:
00575000 > 74 07 JE SHORT mjcs.00575009
00575002 75 05 JNZ SHORT mjcs.00575009
00575004 1932 SBB DWORD PTR DS:[EDX],ESI
00575006 67:E8 E8741F75 CALL 7576C4F4 ; Superfluous prefix
0057500C 1D E8683944 SBB EAX,443968E8
00575011 CD 00 INT 0
00575013 59 POP ECX
00575014 9C PUSHFD
00575015 50 PUSH EAX
00575016 74 0A JE SHORT mjcs.00575022
00575018 75 08 JNZ SHORT mjcs.00575022
0057501A E8 59C20400 CALL 005C1278
0057501F 55 PUSH EBP
00575020 8BEC MOV EBP,ESP
00575022 E8 F4FFFFFF CALL mjcs.0057501B
00575027 56 PUSH ESI
00575028 57 PUSH EDI
00575029 53 PUSH EBX
0057502A 78 0F JS SHORT mjcs.0057503B
0057502C 79 0D JNS SHORT mjcs.0057503B
0057502E E8 34994749 CALL 499EE967
00575033 34 33 XOR AL,33
不知道什么壳,花指令多。
第一步:通过偷窥设法转单进程
想看看此软件到底通过什么标志来进行进程转换.所以偶用
kerberos API spy调入程序,运行后得到log:
This file generated by kerberos API spy v1.02
(C) 2004-2005 Rustem Fasihov <fasihov@mail.ru>
Sat Dec 10 9:47:03 2005
Plugin not installed
Analyzing database...
OK...
Installing hooks
OK...
DLL's in database: 2
DLL's failed to load: 0
Functions in database: 1312
Functions failed to initialize: 0
======================================================================================
======================================================================================
============================
MODULE_NAME RET_ADDR FUNCTION_NAME
======================================================================================
======================================================================================
============================
kernel32.dll | 7C801BE6 | HeapFree(00250000, 00000000, 00253370) returns: 00253901
msvcrt.dll | 77C09FC2 | TlsGetValue(00000001) returns: 003E1E90
msvcrt.dll | 77BFC2DE | HeapFree(003E0000, 00000000, 003E1E90) returns: 00000001
msvcrt.dll | 77C0A0E8 | TlsSetValue(00000001, 00000000) returns: 00000001
IMM32.DLL | 763027A3 | GetKeyboardLayout(00000000) returns: 08040804
ntdll.dll | 7C948571 | HeapFree(00250000, 00000000, 00253028) returns: 00000001
ntdll.dll | 7C948589 | HeapFree(00250000, 00000000, 00253018) returns: 00000001
ntdll.dll | 7C938DAB | TryEnterCriticalSection(7C99C0D8) returns: 00000001
ntdll.dll | 7C948619 | HeapAlloc(00250000, 000C0000, 00000004) returns: 00253018
ntdll.dll | 7C948662 | HeapAlloc(00250000, 000C0000, 00000014) returns: 00253028
kernel32.dll | 7C80B5B1 | GetModuleHandleA(00000000) returns: 00400000
msvcrt.dll | 77BEF0C0 | TlsGetValue(00000001) returns: 00000000
msvcrt.dll | 77BFC1DB | HeapAlloc(003E0000, 00000008, 00000088) returns: 003E1E90
msvcrt.dll | 77BEF0E5 | TlsSetValue(00000001, 003E1E90) returns: 00000001
msvcrt.dll | 77BEF0F6 | GetCurrentThreadId() returns: 00000B40
ntdll.dll | 7C957942 | TryEnterCriticalSection(7C99C0D8) returns: 00000001
mjcs.exe | 0057CA5E | LoadLibraryA(0057BA7E: "kernel32.dll") returns: 7C800000
mjcs.exe | 0057CA81 | LoadLibraryA(0057BA7E: "kernel32.dll") returns: 7C800000
mjcs.exe | 0057B801 | GetProcAddress(7C800000, 0057C8CE: "HeapAlloc") returns: 7C9305D4
mjcs.exe | 0057CAA1 | GetProcessHeap() returns: 00250000
mjcs.exe | 0057CAA4 | HeapAlloc(00250000, 00000008, 00000320) returns: 00253048
mjcs.exe | 0057C7A9 | GetModuleHandleA(0057BA7E: "kernel32.dll") returns: 7C800000
mjcs.exe | 0057CB03 | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057C7C2 | GetModuleHandleA(0057ECC6: "kernel32.dll") returns: 7C800000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B801 | GetProcAddress(7C800000, 0057EEB6: "SetLastError") returns: 7C930340
mjcs.exe | 0057B801 | GetProcAddress(7C800000, 0057EFA4: "HeapAlloc") returns: 7C9305D4
mjcs.exe | 0057B801 | GetProcAddress(7C800000, 0057EFBD: "HeapFree") returns: 7C93043D
mjcs.exe | 0057B801 | GetProcAddress(7C800000, 0057F06A: "GetLastError") returns: 7C930331
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057C7C2 | GetModuleHandleA(0057ECD3: "user32.dll") returns: 77D10000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057C7C2 | GetModuleHandleA(0057ECDE: "advapi32.dll") returns: 77DA0000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B47B | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057B840 | GetProcessHeap() returns: 00250000
mjcs.exe | 0057B846 | HeapAlloc(00250000, 00000008, 0000000C) returns: 002552E8
mjcs.exe | 0057B86B | GetProcessHeap() returns: 00250000
mjcs.exe | 0057B871 | HeapAlloc(00250000, 00000008, 00004000) returns: 00255300
mjcs.exe | 0057B89E | VirtualProtect(00255300, 00004000, 00000040, 0012FFB8) returns: 00000001
mjcs.exe | 00575437 | GetVersion() returns: 0A280105
mjcs.exe | 0057C2F9 | GetModuleHandleA(00000000) returns: 00400000
ntdll.dll | 7C957942 | TryEnterCriticalSection(7C99C0D8) returns: 00000001
mjcs.exe | 005759D1 | GetTickCount() returns: 00401EDA
mjcs.exe | 00575834 | GetTickCount() returns: 00401EDA
mjcs.exe | 00575869 | GetTickCount() returns: 00401EDA
ntdll.dll | 7C957942 | TryEnterCriticalSection(7C99C0D8) returns: 00000001
mjcs.exe | 00575A91 | GetTickCount() returns: 00401EDA
mjcs.exe | 0057C48E | GetVersionExA(0012FF2C) returns: 00000000
mjcs.exe | 0057C2F9 | GetModuleHandleA(00000000) returns: 00400000
mjcs.exe | 0057D369 | GetVersion() returns: 0A280105
mjcs.exe | 0057D38B | LoadLibraryA(0057D353: "Kernel32.dll") returns: 7C800000
mjcs.exe | 0057D3B3 | GetProcessTimes(FFFFFFFF, 0012FFB8, 0012FFB0, 0012FFB0, 0012FFB0)
returns: 00000001
mjcs.exe | 0057D3C1 | GetSystemTimeAsFileTime(0012FFB0) returns: 01C5FD2B
mjcs.exe | 0057D53B | GetVersion() returns: 0A280105
mjcs.exe | 0057D549 | GetTickCount() returns: 00401EDA
mjcs.exe | 0057D566 | LoadLibraryA(0057D52B: "ntdll.dll") returns: 7C920000
mjcs.exe | 0057C572 | wsprintfA(0012FE8C) returns: 00000014
mjcs.exe | 0057C584 | GetTempPathA(00000104, 0012FEBC) returns: 00000023
mjcs.exe | 0057C5B2 | CreateFileA(0012FEBC: "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\~temp0-
26013477...", C0000000, 00000003, 00000000, 00000004, 00000002, 00000000) returns: 00000010
mjcs.exe | 0057C5D1 | ReadFile(00000010, 0012FE80, 00000004, 0012FE88, 00000000) returns:
00000001
mjcs.exe | 0057C5E8 | GetTickCount() returns: 00401EDA
mjcs.exe | 0057C61C | SetFilePointer(00000010, 00000000, 00000000, 00000000) returns: 00000000
mjcs.exe | 0057C630 | WriteFile(00000010, 0012FE80, 00000004, 0012FE88, 00000000) returns:
00000001
mjcs.exe | 0057C6C3 | CloseHandle(00000010) returns: 00000001
mjcs.exe | 00575D53 | GetCommandLineA() returns: 00252398
mjcs.exe | 00575DBF | CreateProcessA(00000000, 0057524C: ""C:\Documents and
Settings\Administrator\", 00000000, 00000000, 00000001, 00000000, 00000000, 00000000, 00575350,
0057523C) returns: 00000001
mjcs.exe | 00575DD7 | ExitProcess(00000000)
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\~temp0
哦,原来通过临时文件来做Flag.
我们在CreateProcessA往上看,找标志,强行转单进程
ollydbg载入,he 575d53 (GetCommandLineA后,要用硬件断点,壳本身检测5个长度的cc)
中断后向上观察:
00575D2E 75 07 JNZ SHORT mjcs.00575D37
00575D30 74 05 JE SHORT mjcs.00575D37
00575D32 0010 ADD BYTE PTR DS:[EAX],DL
00575D34 40 INC EAX
00575D35 00E8 ADD AL,CH
00575D37 0F84 9A000000 JE mjcs.00575DD7 //*****注意这里****
00575D3D E8 01000000 CALL mjcs.00575D43
00575D42 FF58 05 CALL FAR FWORD PTR DS:[EAX+5] ; Far call
00575D45 1100 ADC DWORD PTR DS:[EAX],EAX
00575D47 0000 ADD BYTE PTR DS:[EAX],AL
00575D49 50 PUSH EAX
00575D4A E9 77890000 JMP mjcs.0057E6C6
00575D4F 0010 ADD BYTE PTR DS:[EAX],DL
00575D51 40 INC EAX
00575D52 0050 8B ADD BYTE PTR DS:[EAX-75],DL
00575D55 F8 CLC
00575D56 32C0 XOR AL,AL
HOHO,575d37这里就是Magic Jump,重来强行跳即可转为运行解码进程.
第二步: OEP :
通过观察代码确定是Delphi的程序,寻找OEP,我们he GetModuleHandleA
看堆栈esp处,当发现:
0012FF94 004066D9 /CALL to GetModuleHandleA from mjcs.004066D4
0012FF98 00000000 \pModule = NULL
是从4066d9调用的时候,我们知道oep已经过了。
逐步返回
004C80DF 0055 8B ADD BYTE PTR SS:[EBP-75],DL
004C80E2 EC IN AL,DX ; I/O command
004C80E3 83C4 F0 ADD ESP,-10
004C80E6 53 PUSH EBX
004C80E7 56 PUSH ESI
004C80E8 57 PUSH EDI
004C80E9 B8 387D4C00 MOV EAX,mjcs.004C7D38
004C80EE E8 D5E5F3FF CALL mjcs.004066C8
004C80F3 8B35 50FF4D00 MOV ESI,DWORD PTR DS:[4DFF50] ; mjcs.004E0BF0 ****返回到这里
004C80F9 8B3D 80FD4D00 MOV EDI,DWORD PTR DS:[4DFD80] ; mjcs.004E0BEC
004C80FF B2 01 MOV DL,1
004C8101 A1 A8354200 MOV EAX,DWORD PTR DS:[4235A8]
004C8106 E8 11CCF5FF CALL mjcs.00424D1C
004C810B 8BD8 MOV EBX,EAX
004C810D BA 94824C00 MOV EDX,mjcs.004C8294 ; ASCII "MS Sans Serif"
004C8112 8BC3 MOV EAX,EBX
004C8114 E8 FFCFF5FF CALL mjcs.00425118
004C8119 BA 3C000000 MOV EDX,3C
往上看,看到了add esp,-10,HOHO,可以确定4c80e0就是OEP了
Dump吧!
第三步: IAT处理
ollydbg重新载入,转成本进程运行,he 4c80e0 到了oep后,Imprec上场。
IAT检测范围为: RVA e218c Size 7B8
载入一看基本都识别不了,看来IAT做了处理。
到4e218c看看去!
004E218C 00 00 00 00 A0 4D 14 00 C0 4D 14 00 E0 4D 14 00 ...._M.劳.嗤.
004E219C 00 4E 14 00 20 4E 14 00 40 4E 14 00 60 4E 14 00 .N. N.@N.`N.
004E21AC 80 4E 14 00 42 B9 57 00 A0 4E 14 00 C0 4E 14 00 ?.B棺._N.牢.
004E21BC E0 4E 14 00 00 4F 14 00 20 4F 14 00 40 4F 14 00 辔..O. O.@O.
004E21CC 60 4F 14 00 80 4F 14 00 A0 4F 14 00 C0 4F 14 00 `O.?._O.老.
004E21DC 3A BA 57 00 E0 4F 14 00 00 50 14 00 20 50 14 00 :鹤.嘞..P. P.
004E21EC 40 50 14 00 60 50 14 00 29 BA 57 00 80 50 14 00 @P.`P.)鹤.?.
004E21FC A0 50 14 00 C0 50 14 00 E0 50 14 00 00 51 14 00 _P.佬.嘈..Q.
004E220C 20 51 14 00 40 51 14 00 60 51 14 00 80 51 14 00 Q.@Q.`Q.?.
004E221C A0 51 14 00 C0 51 14 00 E0 51 14 00 00 52 14 00 _Q.姥.嘌..R.
004E222C 20 52 14 00 40 52 14 00 60 52 14 00 80 52 14 00 R.@R.`R.?.
004E223C A0 52 14 00 00 00 00 00 C0 52 14 00 E0 52 14 00 _R.....酪.嘁.
通过观察,基本被指向了动态申请的内存区域 14xxxx
例如,结构如下:
00406604 -FF25 84224E00 JMP DWORD PTR DS:[4E2284]
=> 4e2284里的值为 145400
145400处代码为:
00145400 74 0E JE SHORT 00145410 ; JMP to kernel32.GetModuleHandleA
00145402 75 0C JNZ SHORT 00145410 ; JMP to kernel32.GetModuleHandleA
00145404 E8 1A32534E CALL 4E678623
00145409 A6 CMPS BYTE PTR DS:[ESI],BYTE PTR ES:[EDI]
0014540A 40 INC EAX
0014540B 009A A54000FF ADD BYTE PTR DS:[EDX+FF0040A5],BL
00145411 25 16541400 AND EAX,145416
00145416 29B5 807C0000 SUB DWORD PTR SS:[EBP+7C80],ESI
0014541C 0000 ADD BYTE PTR DS:[EAX],AL
0014541E 0000 ADD BYTE PTR DS:[EAX],AL
做了变形,所以得写代码修复。
找个区域写代码,我到140000处:
00140000 60 PUSHAD
00140001 9C PUSHFD
00140002 BF 8C214E00 MOV EDI,4E218C
00140007 66:837F 02 14 CMP WORD PTR DS:[EDI+2],14
0014000C 75 22 JNZ SHORT 00140030
0014000E 8B17 MOV EDX,DWORD PTR DS:[EDI]
00140010 90 NOP
00140011 90 NOP
00140012 90 NOP
00140013 8B42 12 MOV EAX,DWORD PTR DS:[EDX+12]
00140016 8B18 MOV EBX,DWORD PTR DS:[EAX]
00140018 891F MOV DWORD PTR DS:[EDI],EBX
0014001A 90 NOP
0014001B EB 13 JMP SHORT 00140030
0014001D 90 NOP
0014001E 90 NOP
0014001F 90 NOP
00140020 90 NOP
00140021 90 NOP
00140022 90 NOP
00140023 90 NOP
00140024 90 NOP
00140025 90 NOP
00140026 90 NOP
00140027 90 NOP
00140028 90 NOP
00140029 90 NOP
0014002A 90 NOP
0014002B 90 NOP
0014002C 90 NOP
0014002D 90 NOP
0014002E 90 NOP
0014002F 90 NOP
00140030 83C7 04 ADD EDI,4
00140033 81FF 00304E00 CMP EDI,4E3000
00140039 7D 02 JGE SHORT 0014003D
0014003B ^EB CA JMP SHORT 00140007
0014003D 9D POPFD
0014003E 61 POPAD
二进制代码:
60 9C BF 8C 21 4E 00 66 83 7F 02 14 75 22 8B 17 90 90 90 8B 42 12 8B 18 89 1F 90 EB 13 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 83 C7 04 81 FF 00 30 4E 00 7D 02 EB CA 9D 61
140000处新建EIP,在 14003e popad处设断点运行。
运行后,用imprec载入IAT,发现还有8个是坏的。
这8个壳做了特殊处理,因此我也来特殊处理 :)
找个delphi的程序把iat表保存下来和它对照一下,正确纠正这8个:
e21b0 57b942 GetTickCount
e21dc 57ba3a GetStartupInfoA
e21f4 57ba29 GetCommandLineA
e22dc 57bca8 SearchPathA
e2328 57b9ec GetVersionExA
e232c 57b942 GetVersion
e237c 57ba5a GetCurrentProcessId
e2380 57bba0 GetCurrentDirectoryA
第四步: 完工,优化:
这里可以手工把dump.exe文件里的壳section代码给去掉,然后根据offset删除垃圾代码,修理好以后就可以Imprec Fix IAT了.
好了,测试运行正常.
我写文章目的,是让大家一起探讨解壳思路,还请各路大侠指教几番.
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界