Pe-Panzer分析
今天看见这个帖子被莫名其妙的顶了上来。所以下载下来分析一下。
原贴:http://bbs.pediy.com/showthread.php?t=142151
对作者的友情提醒:
---------------
push 4 //PAGE_READWRITE,请修改为40(PAGE_EXECUTE_READWRTE),这样记事本就不会崩溃了。
push 1000
push dword ptr [ebp+D0]
push 0
call dword ptr [ebp+F9] ; kernel32.VirtualAlloc,您的第一次新加入的区段代码中的第一次调用。
------------------------------------------------
以下是正文:
新加的区段比较好过。以主程序为例:
00440079 > 60 pushad
0044007A 2BD2 sub edx, edx
0044007C 85D2 test edx, edx
0044007E 74 03 je short 00440083
00440080 75 00 jnz short 00440082
00440082 E8 E8000000 call 0044016F
00440087 005F 8D add byte ptr [edi-73], bl
0044008A 7F 23 jg short 004400AF
0044008C 8BF7 mov esi, edi
0044008E 33C9 xor ecx, ecx
00440090 8D89 05040000 lea ecx, dword ptr [ecx+405]
00440096 C1E9 02 shr ecx, 2
00440099 BA 60140000 mov edx, 1460
0044009E 83FA 00 cmp edx, 0
004400A1 74 08 je short 004400AB
004400A3 AD lods dword ptr [esi]
004400A4 33C2 xor eax, edx
004400A6 33C1 xor eax, ecx
004400A8 AB stos dword ptr es:[edi]
004400A9 ^ E2 F8 loopd short 004400A3
004400AB 8961 00 mov dword ptr [ecx], esp 在这里F4再F7
继续往下到这里:
004401C2 55 push ebp
004401C3 FFB5 BC000000 push dword ptr [ebp+BC]
004401C9 53 push ebx
004401CA E8 57000000 call 00440226 F7进入
004401CF 50 push eax
004401D0 53 push ebx
004401D1 E8 2F020000 call 00440405
004401D6 5A pop edx
004401D7 55 push ebp
004401D8 FFE2 jmp edx 等我们从上面440226返回之后在这里点F4再F8
00440226 60 pushad
00440227 8B6C24 2C mov ebp, dword ptr [esp+2C]
0044022B 8D85 C4000000 lea eax, dword ptr [ebp+C4]
00440231 8B10 mov edx, dword ptr [eax]
00440233 8D85 C0000000 lea eax, dword ptr [ebp+C0]
00440239 8B18 mov ebx, dword ptr [eax]
0044023B 52 push edx
0044023C B9 00000000 mov ecx, 0
00440241 8D89 8C030000 lea ecx, dword ptr [ecx+38C]
00440247 C1E9 02 shr ecx, 2
0044024A BA D686C60D mov edx, 0DC686D6
0044024F 8DB5 24010000 lea esi, dword ptr [ebp+124]
00440255 AD lods dword ptr [esi]
00440256 33C2 xor eax, edx
00440258 33C1 xor eax, ecx
0044025A 8BD0 mov edx, eax
0044025C ^ E2 F7 loopd short 00440255
0044025E 95 xchg eax, ebp
0044025F 5A pop edx
00440260 8B4C24 28 mov ecx, dword ptr [esp+28]
00440264 C1E9 02 shr ecx, 2
00440267 8B7C24 24 mov edi, dword ptr [esp+24]
0044026B 8B7424 24 mov esi, dword ptr [esp+24]
0044026F 8D80 DA010000 lea eax, dword ptr [eax+1DA]
00440275 50 push eax
00440276 64:FF35 0000000>push dword ptr fs:[0]
0044027D 64:8925 0000000>mov dword ptr fs:[0], esp
00440284 92 xchg eax, edx F4到这里
00440285 60 pushad
00440286 66:9C pushfw
00440288 804C24 01 01 or byte ptr [esp+1], 1
0044028D 66:9D popfw
0044028F 61 popad
00440290 90 nop 新建EIP
00440291 33D3 xor edx, ebx
00440293 33D1 xor edx, ecx
00440295 33D5 xor edx, ebp
00440297 AD lods dword ptr [esi]
00440298 33C2 xor eax, edx
0044029A AB stos dword ptr es:[edi]
0044029B ^ E2 F4 loopd short 00440291
0044029D 64:8F05 0000000>pop dword ptr fs:[0]
004402A4 83C4 04 add esp, 4
004402A7 61 popad
004402A8 C2 0C00 retn 0C F4到这里再F8返回。
然后就是真正的壳处理部分了。详细写太麻烦,我就简单的贴笔记了。
003C0000 E8 00000000 call 003C0005
003C0005 5A pop edx
003C0006 83EA 05 sub edx, 5 这段自定位就不说了。
003C0009 5D pop ebp
003C000A 8B82 A3050000 mov eax, dword ptr [edx+5A3] 这里看起来像一个结构,中间我们会不断地得出这个结构的部分成员信息。
003C0010 0BC0 or eax, eax
003C0012 74 06 je short 003C001A
003C0014 61 popad
003C0015 E9 1C040000 jmp 003C0436
003C0436 68 00000000 push 0
003C043B C3 retn
[edx+5A3] bIsInitialized
----------------------------------------------
003C001A B9 03000000 mov ecx, 3
003C001F 8D75 28 lea esi, dword ptr [ebp+28]
003C0022 8DBA 7F050000 lea edi, dword ptr [edx+57F]
003C0028 8B06 mov eax, dword ptr [esi]
003C002A 8907 mov dword ptr [edi], eax
003C002C 83C6 04 add esi, 4
003C002F 83C7 04 add edi, 4
003C0032 ^ E2 F4 loopd short 003C0028
ebp+28 440028 pfn_GetProcAddress
44002C pfn_GetModuleHandleA
440030 pfn_LoadLibraryA
copy to edx+57F
3C057F pfn_GetProcAddress
3C0583 pfn_GetModuleHandleA
3C0587 pfn_LoadLibraryA
------------------------------------------------
003C00D3 8B82 CC050000 mov eax, dword ptr [edx+5CC]
003C00D9 83E0 01 and eax, 1
003C00DC 0BC0 or eax, eax
003C00DE 74 0E je short 003C00EE
003C00E0 0F31 rdtsc
003C00E2 91 xchg eax, ecx
003C00E3 0F31 rdtsc
003C00E5 2BC1 sub eax, ecx
003C00E7 3D FF000000 cmp eax, 0FF
003C00EC 7F 1B jg short 003C0109 //GameOver if jump
利用时间差检测是否在虚拟机种运行。
---------------------------------------------
下面基本的思路是看汇编代码,然后还原为C实现,然后推断成员的含义。
3C00BB:
if([ebp+4AB]==0) [ebp+59B]=pfn_GetModuleHandleA(NULL)
ebp+59B ThisImageBase
3C00EE:
if (!(hKernel32=pfn_GetModuleHandleA((ebp+5AB)))) hKernel32=pfn_LoadLibraryA((ebp+5AB))
ebp+5AB "KERNEL32.dll"
3C0108:
[ebp+5A7]=pfn_GetProcAddress(hKernel32,(ebp+5B8))
ebp+5B8 "VirtualFree"
ebp+5A7 pfn_VirtualFree
3C0141:
unsigned int i=0;
while(!(orgSectionDescribeTable[i].VirtualSize))
{
pDecodeBuffer=pfn_VirtualAlloc(NULL,orgSectionDescribeTable[i].VirtualSize,MEM_COMMIT,PAGE_READWRITE);
pDeCryptCodeRoutine(ThisImageBase+orgSectionDescribeTable[i].VirtualAddress,orgSectionDescribeTable[i].CryptedBufferSize,pPackerStart);
pDecompressRoutine(ThisImageBase+orgSectionDescribeTable[i].VirtualAddress,pDecodeBuffer);
memcpyn(ThisImageBase+orgSectionDescribeTable[i].VirtualAddress,pDecodeBuffer,orgSectionDescribeTable[i].VirtualSize);
pfn_VirtualFree(pDecodeBuffer,0,MEM_RELEASE);
i++;
}
3C017F:
[ebp+5D4]=[ebp+4A3] 2DB
pAPI_Steal_Buffer
[ebp+5D8]=[ebp+4A3] 2DB
saved_pAPI_Steal_Buffer
3C0191:
if (*pAPI_Steal_Buffer==2DB) PBYTE pAPI_Steal_Buffer=(PBYTE)pfn_VirtualAlloc
(NULL,0x2E7C,MEM_COMMIT,PAGE_READWRITE);
ebp+5D4 pAPI_Steal_Buffer
[ebp+5DC]=[ebp+5D8];
dAPI_StealMark
3C01BD:
if (!Is_ImportHooked)
{
run when option IsImportTableHOOK is not checked
}
3C025B:
PBYTE pstrName;
if (pstrName=((*pInformationTable)pIAT+pInformationTable)) //first 0xc008
{
DWORD* pImportAddr=ThisImageBase+*((*pInformationTable).pIAT+pInformationTable);
pstrName+=5;
if (*(pstrName+6)=='3' ||*(pstrName+6)=='2') (*pInformationTable).FucntionStealMark='2'; //ebp+5E4,对抗策略,方式1
DWORD hLibrary=Macro_GMH_LB(pstrName); //if GetModuleHandle Failed, then call LoadLibraryA
pstrName+=*(pstrName-1);
DWORD APICount=*(DWORD*)(pstrName);
pstrName+=sizeof(DWORD);
do
{
if(*(pstrName)) //Length of this API Name
{ //Ordinal value Mode
pstrName++;
*pImportAddr=pMyGetProcAddress(hLibrary,pstrName,pfn_LoadLibrayA);
pstrName+=sizeof(DWORD);
}
else
{ //Name Mode
pstrName++;
*pImportAddr=pMyGetProcAddress(hLibrary,*(DWORD*)(pstrName),pfn_LoadLibrayA);
pstrName+=*(pstrName-1)+1;
}
if ((*pInformationTable).dAPI_StealMark==2DB || (*pInformationTable).FucntionStealMark)
{
*pAPI_Steal_Buffer=0x60; //pushad
*(pAPI_Steal_Buffer+1)=0xe8; //call Imm32
*(DWORD*)(pAPI_Steal_Buffer+2)=pApiJmpRoutine-(pAPI_Steal_Buffer+2); //pApiJmpRoutine=(ebp+46c)
*(DWORD*)(pAPI_Steal_Buffer+6)=ApiAddrXorKey ^ *pImportAddr;
*pImportAddr=pAPI_Steal_Buffer;//对抗策略,方式2
pAPI_Steal_Buffer+=10;
}
if (!Is_ImportHooked)//[ebp+5e0]
{
saved_pAPI_Steal_Buffer=pAPI_Steal_Buffer-10;
Is_ImportHooked=Ture;
}
pImportAddr++;
APICount--;
}while(APICount)
}
--------------------------------------------------
3C0374:
PBYTE RelocInfo=RelocDescribeTable+ThisImageBase;
DWORD RelocAdder=ThisImageBase-org_ImageBase;
do
{
PBYTE* prevRelocAddr=0
if (*RelocInfo==3)
{
RelocInfo++;
prevRelocAddr=(PBYTE)(*(DWORD*)RelocInfo+ThisImageBase)
*(DWORD*)prevRelocAddr+=RelocAdder;
RelocInfo+=sizeof(DWORD);
}
else
{
RelocInfo++;
prevRelocAddr+=*(RelocInfo-1);
*(DWORD*)prevRelocAddr+=RelocAdder;
}
}
while (*RelocInfo)
--------------------------------------------------
3C03B1:
__asm{
push dword ptr fs:[30]
pop eax //TEB.PEB
mov eax, dword ptr [eax+C] //PEB.LoaderData
mov eax, dword ptr [eax+C] //PEB.LoaderData.InLoadOrderModuleList
mov dword ptr [eax+20], 1000 //LDR_MODULE.SizeOfImage=1000,antidump
}
do anti via PEB. if Failed, used GetModuleHandle(0), if still failed(edx < 80000000), skip this anti.
---------------------------------------------------
3C03E8:JMP via SEH
003C03E8 55 push ebp
003C03E9 8D85 13040000 lea eax, dword ptr [ebp+413] //3C0413
003C03EF 50 push eax
003C03F0 8D85 3C040000 lea eax, dword ptr [ebp+43C] //3C043C
003C03F6 50 push eax
003C03F7 64:FF35 0000000>push dword ptr fs:[0]
003C03FE 64:8925 0000000>mov dword ptr fs:[0], esp
003C0405 CD 02 int 2 //异常,触发3C043C的处理函数
003C0407 90 nop
003C043C 55 push ebp
003C043D 8BEC mov ebp, esp
003C043F 60 pushad
003C0440 8B75 08 mov esi, dword ptr [ebp+8]
003C0443 8B7D 10 mov edi, dword ptr [ebp+10]
003C0446 8B45 0C mov eax, dword ptr [ebp+C]
003C0449 FF70 08 push dword ptr [eax+8] //3C0413
003C044C 8F87 B8000000 pop dword ptr [edi+B8] //改写EIP
003C0452 FF70 0C push dword ptr [eax+C]
003C0455 8F87 B4000000 pop dword ptr [edi+B4]
003C045B 50 push eax
003C045C 8F87 C4000000 pop dword ptr [edi+C4]
003C0462 61 popad
003C0463 B8 00000000 mov eax, 0
003C0468 C9 leave
003C0469 C2 1000 retn 10
003C0413 64:8F05 0000000>pop dword ptr fs:[0]
003C041A 83C4 0C add esp, 0C
003C041D FF85 A3050000 inc dword ptr [ebp+5A3] //bIsInitialized=1,避免重复执行
003C0423 8B85 9F040000 mov eax, dword ptr [ebp+49F]
003C0429 0385 9B050000 add eax, dword ptr [ebp+59B]
003C042F 0185 37040000 add dword ptr [ebp+437], eax ; PE-panze.00407370
003C0435 61 popad
003C0436 68 00000000 push 0 //上面的数值改写到了这里。
003C043B C3 retn //jmp oep
---------------------------------------------------
成员整理:
003C049F 00007370 OrgEntryPoint
003C04A3 000002DB ImportTableHOOK_Mark
003C04A7 000005E8 pImportTable
003C04AB 00000000
003C04AF 0003F000 RelocDescribeTable //这里的数据含义请参照代码3C0374的C语言实现。
003C04B3 00400000 org_ImageBase
003C04B7 0000B000 orgSectionDescribeTable[org_NumofSection]
struct SectionDescribeTable
{
DWORD VirtualSize;
DWORD VirtualAddress;
DWORD CompressedBufferSize;
DWORD CryptedBufferSize;
}
003C04BB 00001000
003C04BF 00007000
003C04C3 000061CD
003C04C7 00002000 第二个区段
003C04CB 0000C000
003C04CF 00001000
003C04D3 00000243
003C04D7 00005000 第三个区段
003C04DB 0000E000
003C04DF 00001000
003C04E3 000007D9
003C04E7 00021418 第4个区段
003C04EB 000133B0
003C04EF 0001E62C
003C04F3 0001E62C
003C04F7 00001000 第5个区段
003C04FB 0003F000
003C04FF 00001000
003C0503 0000001E
003C0507 00000000
003C050B 00000000
003C050F 00000000
003C0513 00000000
003C0517 00000000
003C051B 00000000
003C051F 00000000
003C0523 00000000
003C0527 00000000
003C052B 00000000
003C052F 00000000
003C0533 00000000
003C0537 00000000
003C053B 00000000
003C053F 00000000
003C0543 00000000
003C0547 00000000
003C054B 00000000
003C054F 00000000
003C0553 00000000
003C0557 00000000
003C055B 00000000
003C055F 00000000
003C0563 00000000
003C0567 00000000
003C056B 00000000
003C056F 00000000
003C0573 00000000
003C0577 00000000
003C057B 00000000
003C057F 7C80AE40 pfn_GetProcAddress
003C0583 7C80B741 pfn_GetModuleHandleA
003C0587 7C801D7B pfn_LoadLibraryA
003C058B 004402AB MyGetProcAddress(hLibrary,pstrName,pfn_LoadLibrayA)
003C058F 00440226 pDeCryptCodeRoutine
003C0593 77D507EA pfn_MessageBoxA
003C0597 7C809AF1 pfn_VirtualAlloc
003C059B 00400000 ThisImageBase
003C059F 00440405 pDecompressRoutine //aPLib
003C05A3 00000001 bIsInitialized
003C05A7 7C809B84 pfn_VirtualFree
003C05AB "KERNEL32.dll"
003C05B8 "VirtualFree"
003C05C4 00001062 unknown,unused
003C05C8 00000FC9 ApiAddrXorKey
003C05CC 0000003F Mark_FutureUsed
High bit
0
1 IsSelfFileCheck
1 IsConfusePEHeader
1 IsImportTableHOOK
1 IsSDK
1 IsRandomKEY
1 IsAntiVM, vm detect via rdtsc
Low bit
003C05D0 00440000 pPackerStart
003C05D4 003D02EE pAPI_Steal_Buffer
003C05D8 003D0000 saved_pAPI_Steal_Buffer
003C05DC 000002DB dAPI_StealMark
003C05E0 0000004B Is_ImportHooked
003C05E4 00000000
003C05E8 0000C008 API填充位置
003C05EC 0C 下一个字符串的长度
003C05ED "KERNEL32.dll"
003C05FA 00000049 这个DLL中需要导入的函数数目
003C05FE 15 下一个字符串的长度
003C05FD "GetPrivateProfileIntA"
003C0615 1A 下一个字符串的长度
003C0616 "WritePrivateProfileStringA"
...
END
SDK是内联函数,这个可以使用SDK的字节代码去匹配起止地址,然后调用SDKOnlyOnceStart相同的代码去解码。
文章结束。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)