fly大侠在
外挂克星脱壳――江湖OnLine V1.05中秋版
http://bbs.pediy.com/showthread.php?s=&threadid=17155
中说道
"看来作者对OllyDBD研究了不少,不过对SoftICE+IceExt却不作抵抗,可惜。"
主程序下载
http://www.szleyu.com/download/BSLYtools.zip
思路:
用SI 跟外挂克星主程序到oep, dump出来, 写1段小程序创建一个新的输入表
, 写1段小程序修正jmp走的IAT操作
开始
2ksp4+ds2.7+iceext
一 到oep
ep 是 2e1d0
bpmb 42e1d0 x
运行 断下
42E1D0 CALL [1000B194] 断下
42E1D6 ADD [EAX], AL
42E1D8 ADD [EAX], AL
42E1DA ADD [EAX], AL
42E1DC ADD [EAX], AL
bpmb 42e1d6 x
bpx.p readprocessmemory
ctrl-d 跑
第三次readprocessmemory断下后,F11返回
9EE556 CALL [KERNEL32!ReadProcessMemory]
9EE55C MOV ESI, 009F7214 F11返回到这儿
9EE561 LEA EAX, [ESP+08]
清除readprocessmemory断点
F10走啊走啊走啊返回这个CALL到这儿
9EFBC7 CALL 009EE3A0
9EFBCC TEST EAX, EAX 到这儿
我这里EAX的返回值是0, 所以不行
r eax 改成 1
然后一路F10 断在ep的下一行42E1D6了
42E1D0 CALL [1000B194]
42E1D6 JMP 40D8CA 断在这儿, 飞向光明之颠
二 dump
基址400000 总大小40000
!dump \??\e:\1.bin 400000 40000
看到oep 开头几行有
40D8EB PUSH ESI
40D8EC PUSH EDI
40D8ED MOV [EBP-18], ESP
40D8F0 JMP 00CD145C 壳把调用API的地方偷走了
到CD145C向上看看,向下看看 发现一张表
CD0048 E1 ED E6 77 FF 15 48 00 CD 00 E9 8D 9F 74 FF 00
......
CD4708 00 92 9B 77 FF 15 08 47 CD 00 E9 1F 00 75 FF AA
反汇编一下CD0048处,意思就是
CD004C CALL [CD0048] 就是 CALL 77E6EDE1
CD0052 JMP 00149FE4 跳回主代码段
这个表也要了
!dump \??\e:\api.bin cd0048 46d0
这时可以清除所有断点, si放掉后, 程序就跑起来了, 程序开在那里
一直会不断的MessageBox, 没办法,忍一下, 我们还要借原程序取输入表
三 修复 1.bin的PE格式
LordPE 打开1.bin
EntryPoint: 2E1D0 -> D8CA
.data (30000, 7CC8, 30000, 4000)->(30000, 7CC8, 30000, 8000)
.rsrc (38000, 71F8, 34000, 8000)->(38000, 71F8, 38000, 8000)
ImportTable(27004, 28) -> (0,0)
IAT(27000, 544) -> (0,0)
1.bin改名1.exe
四 输入表
先做一件事情, 任务管理器关掉Explorer.exe 再打开Explorer.exe, 这样别的进程就能看到它了
原来的IAT是(27000, 544), 借用这块地方
-----------------------------第一个程序---------------------------------
#include <windows.h>
#include <stdio.h>
void main(void)
{
FILE *fp = fopen("e:\\api.bin", "rb");
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, 1360); // 打开外挂克星进程
char apibuf[16];
DWORD dwPrevApiAddr = 0;
DWORD dwApiAddr = 0;
DWORD dwIatAddr = 0x400000 + 0x27000; // IAT地址
DWORD dwWrite;
int r = fread(apibuf, 16, 1, fp);
while (r !=EOF && r != 0)
{
dwApiAddr = *(LPDWORD)apibuf;
if (dwPrevApiAddr != dwApiAddr)
{
// 不带重复的一个个写进去
WriteProcessMemory(h, (LPVOID)dwIatAddr, apibuf, 4, &dwWrite);
dwIatAddr += 4;
}
dwPrevApiAddr = dwApiAddr;
r = fread(apibuf, 16, 1, fp);
}
fclose(fp);
CloseHandle(h);
}
写完后, 用ImportREC 打开外挂克星进程 RVA 27000, SIZE 514
得到的指针就1个, 显示是假的, 别理它
ImportREC的选项 选中 "创建新的IAT", 去掉 "修复ep 到oep"
修复1.exe, 得到1_.exe
五 修正jmp走的IAT操作
可以关掉程序了
---------------------------第二个程序---------------------------------
#include <windows.h>
#include <stdio.h>
void main(void)
{
FILE *fp = fopen("e:\\1_.exe", "rb");
char *mapoffile = new char[0x42000]; //文件大小0x42000
fread(mapoffile, 0x42000, 1, fp); //文件内容全读进来
fclose(fp);
fp = fopen("e:\\api.bin", "rb");
char apibuf[16];
DWORD dwPrevApiAddr = 0;
DWORD dwApiAddr = 0;
DWORD dwIatAddr = 0x400000 + 0x40000;
DWORD dwRCall;
int r = fread(apibuf, 16, 1, fp);
dwPrevApiAddr = *(LPDWORD)apibuf;
while (r !=EOF && r != 0)
{
// 得到IAT的位置
dwApiAddr = *(LPDWORD)apibuf;
if (dwPrevApiAddr != dwApiAddr)
dwIatAddr += 4;
if (*(LPDWORD)(dwIatAddr-0x400000+mapoffile) == 0)
dwIatAddr += 4;
dwPrevApiAddr = dwApiAddr;
// 找偷掉API操作的字节长度
// 比如 CALL [0x00CD****] 是6个字节
// MOV EAX, [0x00CD****] 是5个字节
for (int i=4; i<16; i++)
{
if (*(LPWORD)&apibuf[i] == 0x00CD)
break;
}
//通过跳回去的地址算出跳进来的地址
dwRCall = *(LPDWORD)&apibuf[i-2] + 4 + 5 + *(LPDWORD)&apibuf[i+3];
//把 jmp CD**** 改回 CALL [IAT]. MOV EDI, [IAT] 等等
memcpy((LPVOID)(dwRCall-0x400000+mapoffile), &apibuf[4], i-2-4);
memcpy((LPVOID)(dwRCall-0x400000+mapoffile+i-2-4), &dwIatAddr, 4);
r = fread(apibuf, 16, 1, fp);
}
fclose(fp);
// 2.exe是最终文件
fp = fopen("e:\\2.exe", "wb");
fwrite(mapoffile, 0x42000, 1, fp);
fclose(fp);
delete[] mapoffile;
}
学习
[注意]APP应用上架合规检测服务,协助应用顺利上架!