手脱易语言Armadillo双线程壳完整笔记
以前没有接触过用易语言做的程序。前几天跟了一下比较有特色的程序。放出来自己做个笔记,朋友们也当个参考。
老规矩用PEID查下壳。Armadillo 3.78 - 4.xx -> Silicon Realms Toolworks
朋友们可以看下区段名里有个.ecode呵。呵。十有八九是易语言做的程序。
拉出AFP查下保护方式:!- Protected Armadillo
Protection system (Basic)
!- <Protection Options>
Standard protection or Minimum protection
Enable Import Table Elimination
Enable Nanomites Processing
Enable Memory-Patching Protections
!- <Backup Key Options>
Fixed Backup Keys
!- <Compression Options>
Minimal/Fastest Compression
!- <Other Options>
Store Environment Vars Externally
Use eSellerate Edition Keys
跟最强保护差不了多少。看来找到了一个硬骨头。向下分析
运行程序,观察下。果然是双线程保护。去掉保护转单先。
OD载入
下断 bp OpenMutexA
断下后,找片空白区域补上段代码。这里我们放在00401000处
00401000 60 pushad 记住转为些处为新EIP
00401001 9C pushfd
00401002 68 54FD1200 push 12FD54 ; ASCII "644:A9F31CFBD"
00401007 33C0 xor eax, eax 上面的这个是MutexName可在堆栈里找到
00401009 50 push eax
0040100A 50 push eax
0040100B E8 2FD9407C call kernel32.CreateMutexA
00401010 9D popfd
00401011 61 popad
00401012 - E9 04DA407C jmp kernel32.OpenMutexA
00401017 90 nop
00401018 0000 add byte ptr [eax], al
0040101A 0000 add byte ptr [eax], al
0040101C 0000 add byte ptr [eax], al
运行,断下。去掉断点和添加的代码
下来我们找IAT和OEP
下断 bp GetModuleHandleA
最好在尾巴上下断。
运行找到第一个如下:
00129440 00CE64B5 返回到 00CE64B5 来自 kernel32.GetModuleHandleA
00129444 00D11BB0 ASCII "kernel32.dll"
00129448 00D12B68 ASCII "VirtualAlloc"
0012944C 549D416B
继续找到第二个:
00129440 00CE64D3 返回到 00CE64D3 来自 kernel32.GetModuleHandleA
00129444 00D11BB0 ASCII "kernel32.dll"
00129448 00D12B5C ASCII "VirtualFree"
0012944C 549D416B
马上出来第三个:
0012918C 00CC8C74 返回到 00CC8C74 来自 kernel32.GetModuleHandleA
00129190 00129308 ASCII "kernel32.dll"
00129194 00000000
去掉断点返回用户空间。
向下找到这里:
00CC8CCA /75 05 jnz short 00CC8CD1
00CC8CCC ^|E9 1BFFFFFF jmp 00CC8BEC
00CC8CD1 \8D8D C8FEFFFF lea ecx, dword ptr [ebp-138]
00CC8CD7 51 push ecx
00CC8CD8 FF15 88F0D000 call dword ptr [D0F088] ; kernel32.LoadLibraryA 这是个好标记
00CC8CDE 8B55 F4 mov edx, dword ptr [ebp-C]
00CC8CE1 8B0D 84EFD100 mov ecx, dword ptr [D1EF84]
00CC8CE7 890491 mov dword ptr [ecx+edx*4], e>
00CC8CEA 8B55 F4 mov edx, dword ptr [ebp-C]
00CC8CED A1 84EFD100 mov eax, dword ptr [D1EF84]
00CC8CF2 833C90 00 cmp dword ptr [eax+edx*4], 0
00CC8CF6 75 05 jnz short 00CC8CFD 关键点
00CC8CF8 ^ E9 EFFEFFFF jmp 00CC8BEC
NOP掉关键点。去掉IAT加密。
继续向下看:
00CC8F6A 8B0D 84EFD100 mov ecx, dword ptr [D1EF84]
00CC8F70 893481 mov dword ptr [ecx+eax*4], e>
00CC8F73 ^ E9 74FCFFFF jmp 00CC8BEC
00CC8F78 EB 03 jmp short 00CC8F7D 这里下断
00CC8F7A D6 salc
00CC8F7B D6 salc 这几个都是好标记。
00CC8F7C 8F ??? ; 未知命令
00CC8F7D 8B15 EC5CD200 mov edx, dword ptr [D25CEC]
F9运行,断下来。去掉前面的修改。完成后去断点。
下新断点bp CreatThread
F9,断下,去断点后返回用户空间。
这时候到代码区00401000上全部是红色的新生代码。马上的阳光明媚了。
搜索OEP特征代码,很容易到这里:
0040389F 55 push ebp OEP找到了。
004038A0 8BEC mov ebp, esp
004038A2 6A FF push -1
004038A4 68 F8724000 push 004072F8
004038A9 68 04554000 push 00405504
004038AE 64:A1 00000000 mov eax, dword ptr fs:[0]
004038B4 50 push eax
004038B5 64:8925 00000000 mov dword ptr fs:[0], esp
004038BC 83EC 58 sub esp, 58
004038BF 53 push ebx
004038C0 56 push esi
004038C1 57 push edi
004038C2 8965 E8 mov dword ptr [ebp-18], esp
在OEP头部下断,运行断下来。
想起来前面用AFP查到一项Enable Import Table Elimination
看看是不是:
00407054 7C812ADE kernel32.GetVersionExA
00407058 7C810EF8 kernel32.HeapDestroy
0040705C 7C812BB6 kernel32.HeapCreate
00407060 7C809AE4 kernel32.VirtualFree
00407064 7C809A51 kernel32.VirtualAlloc
00407068 7C9379FD ntdll.RtlReAllocateHeap
混在一起怎么行。请出法宝来。ArmInLine出场了。
专家就是不一样。找的一点不差。New base IAT选哪里呢。在内存里面搜user32.dll 下面有点空间正好可以放新IAT,就他了。
点RebaseIAT。OK。
用LoadPE完整转存。IREC修复。一切正常。你可以哈哈哈大笑了。先慢。会这么容易么?肯定有古怪,难题在后面等着你呢。
运行出错。提示文件里面有错误的数据。???
还得打开调试器载入出错程序,进行我们今天主要经典部分。分解文件。
找特征字符串来到这里:
00401494 C745 FC A880400>mov dword ptr [ebp-4]>; ASCII "The interface of kernel library is invalid!"
0040149B EB 22 jmp short 004014BF
0040149D C745 FC 8C80400>mov dword ptr [ebp-4]>; ASCII "Invalid data in the file!"
004014A4 EB 19 jmp short 004014BF
004014A6 C745 FC 5C80400>mov dword ptr [ebp-4]>; ASCII "Failed to read file or invalid data in file!"
004014AD EB 10 jmp short 004014BF
004014AF C745 FC 8C80400>mov dword ptr [ebp-4]>; ASCII "Invalid data in the file!"
004014B6 EB 15 jmp short 004014CD
004014B8 C745 FC 3880400>mov dword ptr [ebp-4]>; ASCII "Failed to read data from the file!"
出错分类挺细的。看来我们脱的没问题。向上找到函数头,慢慢看。
好熟悉啊。我们列举下主要用到的API就清楚了:
0040115D 895D F0 mov dword ptr [ebp->
00401160 FF15 40506200 call dword ptr [<&ke>; kernel32.GetModuleFileNameA
00401166 53 push ebx
00401167 68 80000000 push 80
0040116C 6A 03 push 3
0040116E 53 push ebx
0040116F 6A 01 push 1
00401171 8D85 6CFEFFFF lea eax, dword ptr >
00401177 68 00000080 push 80000000
0040117C 50 push eax
0040117D FF15 10506200 call dword ptr [<&ke>; kernel32.CreateFileA
00401183 8BF8 mov edi, eax
00401185 83FF FF cmp edi, -1
00401188 75 07 jnz short 00401191
0040118A E9 3E030000 jmp 004014CD
0040118F 90 nop
00401190 90 nop
00401191 8B35 1C704000 mov esi, dword ptr >; kernel32.SetFilePointer
00401197 6A 00 push 0
00401199 53 push ebx
0040119A 68 4DC02100 push 21C04D
0040119F 57 push edi
004011A0 FFD6 call esi
004011A2 90 nop
004011A3 90 nop
004011A4 3D E8030000 cmp eax, 3E8
004011A9 8945 F4 mov dword ptr [ebp->
004011AC 0F82 FD020000 jb 004014AF
004011B2 8D45 E4 lea eax, dword ptr >
004011B5 53 push ebx
004011B6 50 push eax
004011B7 8D45 DC lea eax, dword ptr >
004011BA 6A 08 push 8
004011BC 50 push eax
004011BD 57 push edi
004011BE 895D E4 mov dword ptr [ebp->
004011C1 FF15 0C506200 call dword ptr [<&ke>; kernel32.ReadFile
上面部分简单点。打开自身文件定位文件指针读数据。
00401266 68 04010000 push 104
0040126B FF15 9C506200 call dword ptr [<&ke>; kernel32.GetTempPathA
00401271 85C0 test eax, eax
00401273 75 0C jnz short 00401281
00401275 C745 FC 9881400>mov dword ptr [ebp->; ASCII "Can't retrieve the temporary directory!"
0040127C E9 3E020000 jmp 004014BF
00401281 8B06 mov eax, dword ptr >
00401283 83C6 04 add esi, 4
00401286 50 push eax
00401287 8D85 70FFFFFF lea eax, dword ptr >
0040128D 68 90814000 push 00408190 ; ASCII "E_%X"
00401292 50 push eax
00401293 FF15 00506200 call dword ptr [<&us>; user32.wsprintfA
00401299 8D85 70FFFFFF lea eax, dword ptr >
0040129F 50 push eax
004012A0 8D85 6CFEFFFF lea eax, dword ptr >
004012A6 50 push eax
004012A7 E8 24200000 call 004032D0
004012AC 83C4 14 add esp, 14
004012AF 8D85 6CFEFFFF lea eax, dword ptr >
004012B5 53 push ebx
004012B6 50 push eax
004012B7 FF15 98506200 call dword ptr [<&ke>; kernel32.CreateDirectoryA
004012BD 8D85 6CFEFFFF lea eax, dword ptr >
打开临时文件夹。新建个目录。
我们还注意到了这个数字:
00401247 3945 E8 cmp dword ptr [ebp-18], eax
0040124A 0F85 56020000 jnz 004014A6
00401250 813E A5B79A82 cmp dword ptr [esi], C99AB6F5
00401256 0F85 4A020000 jnz 004014A6
发现我们脱后的这个程序读出来的和数字不付,然后就跳到出错代码处。怪不得要出错了。先不管它,向下看:
00401378 C70424 4C814000 mov dword ptr [esp], 0040814C ; ASCII "krnln.fnr"
0040137F 57 push edi
00401380 8D7406 01 lea esi, dword ptr [esi+eax+1]
00401384 E8 97550000 call 00406920
00401389 59 pop ecx
0040138A 85C0 test eax, eax
0040138C 59 pop ecx
0040138D 74 11 je short 004013A0
0040138F 68 40814000 push 00408140 ; ASCII "krnln.fne"
00401394 57 push edi
00401395 E8 86550000 call 00406920
0040139A 59 pop ecx
0040139B 85C0 test eax, eax
0040139D 59 pop ecx
0040139E 75 0C jnz short 004013AC
004013A0 8D45 A4 lea eax, dword ptr [ebp-5C]
004013A3 57 push edi
004013A4 50 push eax
004013A5 E8 161F0000 call 004032C0
004013AA 59 pop ecx
004013AB 59 pop ecx
004013AC 8B3E mov edi, dword ptr [esi]
004013AE 8D85 6CFEFFFF lea eax, dword ptr [ebp-194]
004013B4 50 push eax
004013B5 8D85 68FDFFFF lea eax, dword ptr [ebp-298]
004013BB 50 push eax
004013BC 83C6 04 add esi, 4
004013BF E8 FC1E0000 call 004032C0
004013C4 FF75 08 push dword ptr [ebp+8]
004013C7 8D85 68FDFFFF lea eax, dword ptr [ebp-298]
004013CD 50 push eax
004013CE E8 FD1E0000 call 004032D0
004013D3 83C4 10 add esp, 10
004013D6 8D85 68FDFFFF lea eax, dword ptr [ebp-298]
004013DC 53 push ebx
004013DD 68 80000000 push 80
004013E2 6A 02 push 2
004013E4 53 push ebx
004013E5 53 push ebx
004013E6 68 00000040 push 40000000
004013EB 50 push eax
004013EC FF15 10506200 call dword ptr [<&kernel32.#80>] ; kernel32.CreateFileA
004013F2 83F8 FF cmp eax, -1
004013F5 8945 08 mov dword ptr [ebp+8], eax
004013F8 74 17 je short 00401411
004013FA 8D4D D8 lea ecx, dword ptr [ebp-28]
004013FD 53 push ebx
004013FE 51 push ecx
004013FF 57 push edi
00401400 56 push esi
00401401 50 push eax
00401402 FF15 58506200 call dword ptr [<&kernel32.#908>] ; kernel32.WriteFile
00401408 FF75 08 push dword ptr [ebp+8]
0040140B FF15 2C506200 call dword ptr [<&kernel32.#50>] ; kernel32.CloseHandle
00401411 03F7 add esi, edi
00401413 3B75 F4 cmp esi, dword ptr [ebp-C]
00401416 ^ 0F82 51FFFFFF jb 0040136D
0040141C 385D A4 cmp byte ptr [ebp-5C], bl
0040141F 75 0C jnz short 0040142D
00401421 C745 FC 2081400>mov dword ptr [ebp-4], 00408120 ; ASCII "Not found the kernel library!"
00401428 E9 92000000 jmp 004014BF
看到那两个奇怪的文件。大家就可以肯定是易语言了。易语言的两种编译方式打包和不打包。打包的那种肯定需要把支持库放出来。
用HEX打开带壳文件和不带壳文件。对比下。发现。我们看到的这些常量在脱完壳的程序里都能找到。只是位置不对。呵。呵。当然了。整个文件大小都变了当然不一样了。
下一步好说,把调试器里面的数据放到脱完壳的程序里面覆盖下,脱壳后文件尾部多出来了一部分,原定位函数从END定不准。我们对程序动下手术从文件首定位。
好了。一切整好后。运行正常,脱壳+修复成功。
谢谢大家观赏。
(PS:不提供附件和程序,拿不出手。大家看出来道道就好)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)