![]() |
来源:安全中国 |
下面我尝试着来修复CC。cc实际上就是int3指令,armadillo把程序中的一些跳转指令改成int3。子进程运行到int3时发生异常,父进程可以捕捉到,然后计算出子进程该不该跳转,如果跳转,跳转量是多少,如果不跳转,下一条指令应从哪里开始。通过getthreadcontext和setthreadcontext函数来干预子进程的运行。因此程序脱壳后,里面的int3指令不修复成原本的跳转指令,程序是不可能运行起来的。 但问题是:脱壳程序中哪些cc是int3指令,哪些cc是数据呢?原先版本的armardillo可以完全区分开来,但现在的版本好像不能够区分,至少我没有找到方法,不知高手们是采用什么办法的。从技术角度来讲,armadillo可以不用区分。我们试想一下:armardillo可以把原程序中所有跳转指令都改成int3,然后连同程序中的cc数据一起进行计算得到一张总表。在加壳时却只随机选一些跳转指令改成int3,但使用的还是那张总表。程序完全可以运行。但我们怎么才能知道总表中哪些是跳转指令呢?我觉得不能,因此也就很难完美修复。 我想到修复的方法有两种,一是在OD中运行加壳程序,设置条件记录断点,然后把程序所有的功能都运行一遍,得到子进程发生int3的地址。二是设计一代码分析器,分析脱壳程序中哪些是int3指令,哪些不是。这两种方法都不能算是完美修复。我的方法是借用OD来找到int3。 我们的目标是得到四个表:int3地址表、跳转类型表、跳转量表及跳转指令长度表。有了这四个表,我们就可以修复cc了。 我们先看第一张int3地址表。在od中打开脱壳程序,从401000~98cfff都是程序的内容,包括代码和资源。armadillo把它们放在同一节中。查找二进制55 8b ec(PUSH EBP MOV EBP, ESP)找到代码开始的部分在5fe660。把5fe660~98cfff选上然后复制到文件中,用ultraedit打开文件,选上“列出包含字符串的行”,查找文本int3。ok,找到如下形式的int3: 0060063E CC INT3 0060063F CC INT3 0060D481 CC INT3 0060D482 CC INT3 0060D483 CC INT3 ..... 使用ultraedit的列编辑功能编辑成: 3E 06 60 00 3F 06 60 00 81 D4 60 00 82 D4 60 00 83 D4 60 00 84 D4 60 00 ..... 当然这里面有很多都是不符合条件的,是int3原始表。先保存好,下面要用。 在OD中重新打开BMP.exe。下he GetThreadContext,运行,第二次停住时,看堆栈窗: 0012DA78 009EBC88 /CALL to GetThreadContext from BMP.009EBC82 0012DA7C 00000050 |hThread = 00000050 (window) 0012DA80 0012E10C \pContext = 0012E10C 在follow in dump 来到0012E10C。按alt+f9回到用户空间。 0012E1AC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0012E1BC 00 00 00 00 64 EE 12 00 DC 37 79 00 1B 00 00 00 ....d?.?y.... 0012E1CC 46 02 00 00 24 EE 12 00 23 00 00 00 00 00 00 00 F..$?.#....... 12e1c4处的7937dc就是子进程发生的第一个int3地址+1,我们可以用OD把脱壳程序打开看看,运行出的第一个错也是那。 0012E1CC处的246是子进程的Flag寄存器内容。 009EBC82 CALL DWORD PTR DS:[<&KERNEL32.GetThreadC>; 009EBC88 PUSH EAX //停在这,这条指令到009EBCCA都是垃圾指令 009EBC89 NOT EAX 009EBC8B BSWAP EAX 009EBC8D POP EAX 009EBC8E JNB SHORT BMP.009EBC90 009EBC90 PUSHFD 009EBC91 PUSHAD 009EBCC1 MOV EAX, C80F9D61 009EBCC6 NOT ECX 009EBCC8 BSWAP EAX 009EBCCA NOT ECX 009EBCCC MOV DWORD PTR SS:[EBP-1468], 0 009EBCD6 PUSH -1 009EBCD8 PUSH 4 009EBCDA LEA EDX, DWORD PTR SS:[EBP-13AC] ; [12e1c4]=7937dc,子进程发生int3的地址+1 009EBCE0 PUSH EDX 009EBCE1 CALL BMP.009D4F90 ; 对int3地址运算 009EBCE6 ADD ESP, 0C 009EBCE9 MOV DWORD PTR SS:[EBP-1194], EAX ; 运算结果 009EBCEF MOV EAX, DWORD PTR SS:[EBP-1194] 009EBCF5 XOR EDX, EDX 009EBCF7 MOV ECX, 10 009EBCFC DIV ECX ; 运算结果除以10 009EBCFE MOV DWORD PTR SS:[EBP-1198], EDX ; 取余数 009EBD04 MOV EDX, DWORD PTR SS:[EBP-13AC] ; int3地址+1 009EBD0A PUSH EDX 009EBD0B MOV EAX, DWORD PTR SS:[EBP-1198] ; 前面得到的余数 009EBD11 CALL DWORD PTR DS:[EAX*4+A15838] ; 再次运算。 009EBD18 ADD ESP, 4 009EBD1B MOV DWORD PTR SS:[EBP-1468], EAX ; 运算结果,将用于在table1(int3地址计算结果表)中查找 009EBD21 >MOV DWORD PTR SS:[EBP-146C], 0 009EBD2B MOV ECX, DWORD PTR SS:[EBP-1198] 009EBD31 MOV EDX, DWORD PTR DS:[ECX*4+A176D4] 009EBD38 MOV DWORD PTR SS:[EBP-118C], EDX 009EBD3E MOV EAX, DWORD PTR SS:[EBP-146C] 009EBD44 CMP EAX, DWORD PTR SS:[EBP-118C] 009EBD4A JGE SHORT BMP.009EBDA8 009EBD4C MOV EAX, DWORD PTR SS:[EBP-118C] 009EBD52 SUB EAX, DWORD PTR SS:[EBP-146C] 009EBD58 CDQ 009EBD59 SUB EAX, EDX 009EBD5B SAR EAX, 1 009EBD5D MOV ECX, DWORD PTR SS:[EBP-146C] 009EBD63 ADD ECX, EAX 009EBD65 MOV DWORD PTR SS:[EBP-1470], ECX 009EBD6B MOV EDX, DWORD PTR SS:[EBP-1198] ; 前面得到的余数 009EBD71 MOV EAX, DWORD PTR DS:[EDX*4+A1768C] ; [A1768C]开始的是table1地址表,根据前面得到的余数找到table1的地址 009EBD78 MOV ECX, DWORD PTR SS:[EBP-1470] 009EBD7E MOV EDX, DWORD PTR SS:[EBP-1468] 009EBD84 CMP EDX, DWORD PTR DS:[EAX+ECX*4] 009EBD87 JBE SHORT BMP.009EBD9A 009EBD89 MOV EAX, DWORD PTR SS:[EBP-1470] 009EBD8F ADD EAX, 1 009EBD92 MOV DWORD PTR SS:[EBP-146C], EAX 009EBD98 JMP SHORT BMP.009EBDA6 009EBD9A MOV ECX, DWORD PTR SS:[EBP-1470] 009EBDA0 MOV DWORD PTR SS:[EBP-118C], ECX 009EBDA6 JMP SHORT BMP.009EBD3E 009EBDA8 PUSHAD ; eax=查表结果(前面运算结果在table1中的序号) 009EBDA9 NOP ....... //nop掉垃圾指令 009EBDCB NOP 009EBDCC NOP 009EBDCD POPAD 009EBDCE MOV EDX, DWORD PTR SS:[EBP-1198] 前面的余数 009EBDD4 MOV EAX, DWORD PTR DS:[EDX*4+A1768C] ; table1地址 009EBDDB MOV ECX, DWORD PTR SS:[EBP-146C] 009EBDE1 MOV EDX, DWORD PTR DS:[EAX+ECX*4] 009EBDE4 CMP EDX, DWORD PTR SS:[EBP-1468] ; 再比较一下,看是否相等 009EBDEA JNZ BMP.009EC102 ........ // 垃圾指令 009EBE47 MOV EAX, DWORD PTR SS:[EBP-1198] 前面的余数 009EBE4D MOV ECX, DWORD PTR DS:[EAX*4+A17714] ; table2(跳转类型代号表) 009EBE54 MOV EDX, DWORD PTR SS:[EBP-146C] 009EBE5A XOR EAX, EAX 009EBE5C MOV AL, BYTE PTR DS:[ECX+EDX] ; 得到跳转类型代号 009EBE5F MOV DWORD PTR SS:[EBP-1488], EAX 009EBE65 MOV EAX, DWORD PTR SS:[EBP-1488] 009EBE6B CDQ 009EBE6C AND EDX, 0F 009EBE6F ADD EAX, EDX 009EBE71 SAR EAX, 4 009EBE74 MOV DWORD PTR SS:[EBP-1480], EAX 009EBE7A MOV ECX, DWORD PTR SS:[EBP-1488] 009EBE80 AND ECX, 8000000F 009EBE86 JNS SHORT BMP.009EBE8D 009EBE88 DEC ECX 009EBE89 OR ECX, FFFFFFF0 009EBE8C INC ECX 009EBE8D MOV DWORD PTR SS:[EBP-1484], ECX 009EBE93 MOV EDX, DWORD PTR SS:[EBP-1480] 009EBE99 CMP EDX, DWORD PTR SS:[EBP-1484] 009EBE9F JNZ SHORT BMP.009EBEBC 009EBEA1 MOV EAX, DWORD PTR SS:[EBP-1484] 009EBEA7 ADD EAX, 1 009EBEAA AND EAX, 8000000F 009EBEAF JNS SHORT BMP.009EBEB6 009EBEB1 DEC EAX 009EBEB2 OR EAX, FFFFFFF0 009EBEB5 INC EAX 009EBEB6 MOV DWORD PTR SS:[EBP-1484], EAX 009EBEBC MOV ECX, DWORD PTR SS:[EBP-1488] 009EBEC2 MOV EDX, DWORD PTR SS:[EBP-1480] 009EBEC8 MOV EAX, DWORD PTR DS:[ECX*4+A16ED0] 009EBECF XOR EAX, DWORD PTR DS:[EDX*4+A1125C] 009EBED6 MOV ECX, DWORD PTR SS:[EBP-1484] 009EBEDC XOR EAX, DWORD PTR DS:[ECX*4+A1125C] 009EBEE3 MOV DWORD PTR SS:[EBP-1478], EAX 009EBEE9 MOV EDX, DWORD PTR SS:[EBP-13A4] ; 子进程context的flag寄存器内容 009EBEEF AND EDX, 0FD7 009EBEF5 PUSH EDX 009EBEF6 MOV EAX, DWORD PTR SS:[EBP-1488] ; 跳转类型代号 009EBEFC MOVSX ECX, BYTE PTR DS:[EAX+A15730] 009EBF03 CALL DWORD PTR DS:[ECX*4+A15838] 009EBF0A ADD ESP, 4 009EBF0D MOV DWORD PTR SS:[EBP-1474], EAX 009EBF13 MOV EDX, DWORD PTR SS:[EBP-13B8] 子进程context的ecx内容 009EBF19 PUSH EDX 009EBF1A MOV EAX, DWORD PTR SS:[EBP-1474] 009EBF20 PUSH EAX 009EBF21 CALL DWORD PTR SS:[EBP-1478] 009EBF27 ADD ESP, 8 009EBF2A PUSH EAX 009EBF2B MOV ECX, DWORD PTR SS:[EBP-1488] 009EBF31 MOVSX EDX, BYTE PTR DS:[ECX+A15730] 009EBF38 CALL DWORD PTR DS:[EDX*4+A15878] 009EBF3F ADD ESP, 4 009EBF42 MOV DWORD PTR SS:[EBP-147C], EAX 009EBF48 MOV EAX, DWORD PTR SS:[EBP-147C] 009EBF4E AND EAX, 1 009EBF51 TEST EAX, EAX //经过若干次复杂计算最后得到子进程在7937dc处是跳呢(eax=1),还是不跳(eax=0) 009EBF53 JE BMP.009EC007 009EBF59 PUSHAD 009EBF7E POPAD 009EBF7F MOV ECX, DWORD PTR SS:[EBP-1198] //如果eax=1,到这 009EBF85 MOV ECX, DWORD PTR DS:[ECX*4+A1764C] 009EBF8C MOV EAX, DWORD PTR SS:[EBP-146C] 009EBF92 XOR EDX, EDX 009EBF94 MOV ESI, 10 009EBF99 DIV ESI 009EBF9B MOV EAX, DWORD PTR SS:[EBP-146C] 009EBFA1 MOV ECX, DWORD PTR DS:[ECX+EAX*4] 009EBFA4 XOR ECX, DWORD PTR SS:[EBP+EDX*4-1170] //得到跳转量 009EBFAB MOV EDX, DWORD PTR SS:[EBP-13AC] 009EBFB1 ADD EDX, ECX 009EBFB3 MOV DWORD PTR SS:[EBP-13AC], EDX //重新设置context |