简单分析 FuckProtect 1.0.0.7 CodeReplace
本帖最后由 ShaBility 于 2010-8-7 10:26 编辑FuckProtect 1.0.0.7 试炼品下载: http://www.52pojie.cn/thread-51624-1-2.html
ximo牛研制的壳,很好很强大,脱壳过程不再说,因为之前已经有人发脱文了。
这次只简单分析一下CodeReplace(可以下载附件进行调试,已脱壳)
OD载入,随便点进一个CALL
004020B3 55 push ebp
004020B4 E8 C7AC0000 call 0040CD80 ; <-CodeReplace
004020B9 56 push esi
004020BA FF75 14 push dword ptr ss:
004020BD FF75 10 push dword ptr ss:
004020C0 FF75 0C push dword ptr ss:
004020C3 FF75 08 push dword ptr ss:
004020C6 E8 A70B0000 call 00402C72
004020CB 85C0 test eax, eax
004020CD 75 09 jnz short 004020D8
004020CF C745 EC 0000000>mov dword ptr ss:, 0
004020D6 EB 73 jmp short 0040214B ; <-CodeReplace
004020D8 E8 A3AC0000 call 0040CD80
004020DD 56 push esi
点进看看
0040CD80 60 pushad
0040CD81 8B5424 20 mov edx, dword ptr ss:
0040CD85 83EA 05 sub edx, 5
0040CD88 52 push edx ; 获取被代码替换的地址
0040CD89 E8 D2FFFFFF call 0040CD60
进入到call 0040CD60
0040CD60 8B5424 04 mov edx, dword ptr ss: ; 被代码替换的地址
0040CD64 33C0 xor eax, eax
0040CD66 81F2 10200000 xor edx, 2010 ; 异或0x2010
0040CD6C B9 00D54000 mov ecx, 0040D500 ; 关键点1
0040CD71 3B11 cmp edx, dword ptr ds:
0040CD73 74 06 je short 0040CD7B
0040CD75 40 inc eax
0040CD76 83C1 04 add ecx, 4 ; 判断下一个DWORD
0040CD79^ EB F6 jmp short 0040CD71
0040CD7B C3 retn
关键点1是啥呢 Ctrl+G 0040D500
0040D50000403249111_.00403249
0040D5040040324E111_.0040324E
0040D508004034B8111_.004034B8
0040D50C00403603111_.00403603
0040D5100040365BASCII "P@"
0040D514004036FD111_.004036FD
0040D5180040394C111_.0040394C
0040D51C00403C75111_.00403C75
0040D52000403D32111_.00403D32
0040D52400403D37111_.00403D37
0040D52800403D21111_.00403D21
0040D52C00403D9C111_.00403D9C
0040D53000403DB5111_.00403DB5
0040D53400403EF2111_.00403EF2
0040D538004000A4111_.004000A4 //edx的值
0040D53C004000C8111_.004000C8
0040D54000400182111_.00400182
0040D5440040021B111_.0040021B
0040D54800400202111_.00400202
0040D54C00400209111_.00400209
0040D55000400255111_.00400255
0040D5540040027B111_.0040027B
0040D558004002DA111_.004002DA
0040D55C00400343111_.00400343
0040D56000400397111_.00400397
0040D564004003E8111_.004003E8
0040D56800400451111_.00400451
0040D56C00400456111_.00400456
原来,0040D500 就是保存了各个被代码替换的地址 知道了这些,继续跑下去吧
0040CD8E 8DB480 00DF4000 lea esi, dword ptr //关键点2
0040CD95 33C9 xor ecx, ecx
0040CD97 E8 00000000 call 0040CD9C
0040CD9C 5D pop ebp
0040CD9D 81ED 4C1F4000 sub ebp, 00401F4C
0040CDA3 8DBD 861F4000 lea edi, dword ptr //edi=0040CDD6 预留空位写原来的代码
其实,关键点2就是偷的代码,其算法为:
(GetCall- 40D500)+((GetCall- 40D500)/4)+40DF00
GetCall就是0040D500 保存的被代码替换的地址
Ctrl+G 0040CDD6
0040CDD6 90 nop //这就是预留的空位
0040CDD7 90 nop
0040CDD8 90 nop
0040CDD9 90 nop
0040CDDA 90 nop
0040CDDB 68 90909090 push 90909090
0040CDE0 C3 retn
0040CDA9 B9 05000000 mov ecx, 5 //偷的是5个字节
0040CDAE F3:A4 rep movs byte ptr es:, byte ptr //写入
0040CDB0 83EF 05 sub edi, 5
0040CDB3 33C0 xor eax, eax
0040CDB5 8BC8 mov ecx, eax
0040CDB7 8A040F mov al, byte ptr
0040CDBA 34 28 xor al, 28 //开始解密,每个字节异或0x28
0040CDBC 3E:880439 mov byte ptr , al
0040CDC0 41 inc ecx
0040CDC1 83F9 05 cmp ecx, 5
0040CDC4 ^ 72 F1 jb short 0040CDB7 //判断是否解密完
0040CDC6 5A pop edx //edx=被代码替换的地址
0040CDC7 83C2 05 add edx, 5 //返回地址
0040CDCA 8DBD 8C1F4000 lea edi, dword ptr
0040CDD0 8917 mov dword ptr , edx //修正返回地址
0040CDD2 61 popad
0040CDD3 83C4 04 add esp, 4 //后面的代码处有入栈操作,故ESP+4
0040CDD6 8BEC mov ebp, esp //被偷的代码已经写回来了
0040CDD8 83EC 1C sub esp, 1C
0040CDDB 68 90909090 push 90909090
0040CDE0 C3 retn
因为40d500 保存被代码替换的地址和保存偷代码的 40DF00都是硬编码,所以我们可以写个修复程序,贴上关键源码
//把需要修复的程序改名为fuck.exe,修复前请备份
int main()
{
//这个可以自己修改
char szFilename = "fuck.exe";
int sel;
UINT i=0, count=0;
hFile = CreateFile(
szFilename,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Fail to open file\n");
getchar();
return 0;
}
if (CreateMap()==FALSE)
{
printf("Error\n");
getchar();
return 0;
}
if (IsPE()==FALSE)
{
printf("Error\n");
getchar();
return 0;
}
while(1)
{
//判断是否最后一个区段
printf("File must be DUMPED!!!\nImpRec Fixed? 1:Yes|2:No\n->");
scanf("%d", &sel);
if (sel == 1 || sel ==2)
{
break;
}
}
PIMAGE_DOS_HEADER imDos = PIMAGE_DOS_HEADER(lpBase);
PIMAGE_NT_HEADERS imNt = PIMAGE_NT_HEADERS((DWORD)lpBase + imDos->e_lfanew);
PIMAGE_SECTION_HEADER imSec = PIMAGE_SECTION_HEADER((DWORD)imNt + sizeof(IMAGE_NT_HEADERS));
i = imNt->FileHeader.NumberOfSections;
i--;
if (sel == 1)
{
i--;
}
PIMAGE_SECTION_HEADER imfkSec = PIMAGE_SECTION_HEADER((DWORD)imSec + sizeof(IMAGE_SECTION_HEADER) * i);
DWORD dwGetCallRVA = 0x1500 + imfkSec->VirtualAddress;
DWORD dwGetCallOffset = RVAToOffset(dwGetCallRVA);
DWORD dwCrOffset = RVAToOffset((dwGetCallRVA + 0xA00));
DWORD dwCallAddr, dwRead;
BYTE bCr = "";
DWORD dwWrite;
while (1)
{
//读被代码替换的地址
SetFilePointer(hFile, dwGetCallOffset,NULL,FILE_BEGIN);
ReadFile(hFile,&dwCallAddr,sizeof(DWORD),&dwRead,NULL);
if (dwCallAddr == 0x0)
{
break;
}
dwCallAddr ^=0x2010;
//printf("%08X : ", dwCallAddr);
SetFilePointer(hFile, dwCrOffset,NULL,FILE_BEGIN);
ReadFile(hFile, &bCr, sizeof(bCr), &dwRead, NULL);
for (i = 0; i < 5; i++)
{
bCr ^= 0x28;
//printf("%02X ", bCr);
}
dwCallAddr = RVAToOffset((dwCallAddr-imNt->OptionalHeader.ImageBase));
SetFilePointer(hFile, dwCallAddr,NULL,FILE_BEGIN);
//修复
WriteFile(hFile, &bCr, sizeof(bCr), &dwWrite, NULL);
//printf("\n");
count++;
dwCrOffset += sizeof(bCr);
dwGetCallOffset += sizeof(DWORD);
}
printf("Replace : %d\n", count);
printf("File Fixed\n");
SetEndOfFile(hFile);
DeleteMap();
getchar();
getchar();
return 0;
}
写得比较挫,都是抄的。:lol :rggrg 哎,又被爆菊了。:'(weeqw 哎,又被爆菊了。
ximo 发表于 2010-8-6 23:05 http://www.52pojie.net/images/common/back.gif
比你写的那两个垃圾文章牛多了...膜拜晕四大牛! 93太牛了 闭关了这么久 太强了 晕死牛进步很快啊. 呵呵,很深哦 本广告位招租!:Dweeqw 很强大。。。 又是一小马甲? 很强大。。。:victory: