EasyPDF v1.5.2 是用Visual Protect 3加的殼
被重定向的import table 都是kernel32.dll, user32.dll等
其重定向方式為
IAT [0068C208] = 01BFAC18
01BFAC18:
B84CC39200 mov eax, 0092C34C
FFE0 jmp eax
0092C34C:
B88818F7BF mov eax, BFF71888 <-- GetCurrentThreadId
FFE0 jmp eax
看上去很簡單, 但Import REConstructor v1.2 的 Trace Level1 (Disasm)是不能分析這種重定向方式的,
因此我們只能手動重建了, 逐個將 BFxxxxxx 填回去是一件非常累人的事情, 幸好其redirect方式很固定,
都是mov eax, xxxxxxxx, jmp eax 每次的程式碼不同之處只是 xxxxxxxx , 我們可以寫個程式來讀
IAT 指向的第1, 6, 7位元組是否分別為 B8, FF, E0, 是就認為這是個有效的redirect, 再根據第5個位元組
比 B0 大, 不是就以2--5位元組為指向下一個jmp的地址再讀, 是就認為這個DWORD是真正的Import Table Address,
將其寫到 IAT處 (如上例的[0068C208]). 然後處理下一個 IAT, 直到 IAT size / 4 個為止.
下面附上源程式, 四個引數 m_processid(程式ID), m_imagebase(IMAGE BASE), m_iatrva(IAT RVA),
m_iatsize(IAT SIZE)
(為什麼是 m_xxxxx ? , 呵呵是VC裡搬過來的(:)
這樣處理完以後就剩下一個被重定向為 0089EF0C 的IAT, debug 看一下, 看其push進去的引數和返回結果就知道這是GetProcAddress.
EasyPDF.exe 重建好了, vspdf.dll也差不多, Process ID 就是 EasyPDF.exe的, 關鍵是找到 IAT RVA 和
IAT SIZE, 其 OEP 是 0x1000,
不過Import REConstructor說找不到IAT, 我試了 OEP 為 0x1CBC0 就能發現 IAT, 但 size 好像也不對, 我也沒仔細看,
反正我是把它改大了.
對那些沒用的IAT都 cut 掉. 還有就是EasyPDF.exe 的 662082 jz near xxxxxxxx. 好, 大功告成。
// file name exp.cpp
// compile with "cl exp.cpp user32.lib"
#include <windows.h>
void main( void )
{
DWORD m_processid, m_imagebase, m_iatrva, m_iatsize;
m_processid = 0xFFF529C6;
m_imagebase = 0x00400000;
m_iatrva = 0x0028C204;
m_iatsize = 0x00000A0C;
unsigned char buf[MAX_PATH];
HANDLE h_process;
DWORD dw_ImageBase = 0x400000;
unsigned int *p_iatva, *p_first_iatrva, *p_NextRedirect;
unsigned long *p_oldprotection=0;
int num, NestedCount, i;
dw_ImageBase = m_imagebase;
num = m_iatsize/4;
__try
{
p_first_iatrva = (unsigned int*) m_iatrva;
if ( (h_process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ
| PROCESS_VM_WRITE, false, m_processid)) != NULL )
{
p_iatva = (unsigned int *) ((unsigned
int)p_first_iatrva + dw_ImageBase);
for(i=0; i<num; i++)
{
if( ReadProcessMemory(
h_process, (void *)p_iatva, buf, 4, 0 ) )
{
p_NextRedirect
= (unsigned int*) buf;
p_NextRedirect
= (unsigned int*) *p_NextRedirect;
for(
NestedCount=0; NestedCount<5; NestedCount++)
if( ReadProcessMemory( h_process, (void *)p_NextRedirect, buf, 10,
0 ) )
{
if (*buf == 0xB8 && *(buf+5) == 0xff
&& *(buf+6) == 0xe0) //mov eax, hhxxxxxx
{
//jmp eax
p_NextRedirect = (unsigned
int *)(void *) (buf + 1);
p_NextRedirect = (unsigned
int*) *p_NextRedirect;
if ( *(buf+4) < 0xB0 )
//when hh >= 0xb0 assume it is the real import address,
only test on my ME.
continue;
//Visual Protect seem to redirect
kernel32.dll, user32.dll ... only.
else
{
if(!VirtualProtectEx(h_process,
(void *)p_iatva, 4, PAGE_READWRITE, p_oldprotection))
{
MessageBox(0, "Error changing access protection of process!", "exp",
MB_OK);
break;
}
if(!WriteProcessMemory(h_process,
(void *)p_iatva, (void *)(buf+1), 4, 0))
{
wsprintf( (char *) buf,"Write process memory error at %x , error
code : %x", p_iatva, GetLastError());
MessageBox(0, (char *) buf, "exp", MB_OK | MB_ICONERROR);
break;
}
else
break; //next iat
}
}
else
break; //does not match format
or already write
}
else
{
//MessageBox(0, "Read process memory error!",
"exp", MB_OK | MB_ICONERROR);
break;
}
}
else
MessageBox(0,
"Read process IAT memory error!", "exp", MB_OK | MB_ICONERROR);
p_iatva ++; //get
next iat
}
MessageBox(0, "Write process memory end.",
"exp", MB_OK | MB_ICONINFORMATION);
}
else
MessageBox(0, "Can not open process!",
"exp", MB_OK | MB_ICONERROR);
}
__except(1)
{
MessageBox(0, "Found exception!!!", "exp", MB_OK | MB_ICONERROR);
}
CloseHandle(h_process);
}