主要是爲了練習一下彙編語言編成和pe文件結構。
#include<stdio.h>
#include<windows.h>
//winnt.h
char *OutputDebug="OutputDebugStringA\0";//length=0x12
DWORD KernelBase=0x7c800000;//方便試驗,直接用工具讀的一個值
WORD dMZ=0;
WORD dNumberOfSections=0;
DWORD e_lfanew=0;
DWORD dSignature=0;
WORD wSizeOfOptionalHeader=0;
DWORD DataDirExport=0;
DWORD SectionVA=0,SectionVS=0,SectionHeaderPTRD;
DWORD NumberOfNames=0;
DWORD FuncIndex=0;
DWORD FuncAddr=0;
DWORD sell()
{
_asm
{
mov eax,KernelBase
mov bx,word ptr [eax]
mov dMZ,bx
cmp bx,0x5a4d;MZ標示
jnz retu
mov ebx,dword ptr [eax+0x3c];獲取PE頭偏移
mov e_lfanew,ebx
test ebx,ebx
jz retu
mov ecx,dword ptr [eax+ebx]
mov dSignature,ecx
cmp ecx,0x4550;PE標示
jnz retu
mov cx,word ptr [eax+ebx+4+16]
mov wSizeOfOptionalHeader,cx
;直接讀的結構體裏面的偏移,這個用winDbg看可能比較直觀一點
mov edx,dword ptr [eax+ebx+0x78];nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EPORT].VirtualAddress
mov DataDirExport,edx
mov dx,word ptr [eax+ebx+4+2];ImageNtHeaders.ImageFileHeader.NumberOfSection
mov dNumberOfSections,dx
find_sec:
mov ecx,dword ptr [eax+ebx+0xf8+0xc];SectionHeader.VirtualAddress
mov SectionVA,ecx
cmp dword ptr [eax+ebx+0x78],ecx
jl next_sec
add ecx,dword ptr [eax+ebx+0xf8+0x8];SectionHeader.Misc.VirtualSize
cmp dword ptr [eax+ebx+0x78],ecx
jl find
next_sec:
dec dx
jnz find_sec
jmp retu
find:
mov edx,dword ptr [eax+ebx+0x78];因爲模塊已經加載到內存,這裏可以直接用這個偏移加模塊基址,和從本地文件讀取有點差別
mov ecx,dword ptr [eax+edx+0x18];ImageExportDirectory.NumberOfNames
mov NumberOfNames,ecx
mov edx,dword ptr [eax+edx+0x20];ImageExportDirectory.AddressOfNames;存函數名稱字符串的偏移,這裏相當於一個數組
push ebx
push ecx
add edx,eax;加上基址
mov ebx,OutputDebug;要找的函數名稱
mov esi,ebx
xor ebx,ebx
;int 3
find_func_name:
mov ecx,18
push esi
mov edi,dword ptr [edx+4*ebx];從字符串數組中取值比較
add edi,eax
repe cmps ;字符串循環比較,ecx爲0或不等,結束比較
test ecx,ecx
jz get_func
pop esi
inc ebx
pop ecx
cmp ebx,ecx
push ecx
jl find_func_name
jmp search_done
get_func:
mov FuncIndex,ebx;保存函數標號
mov edi,ebx
pop esi
pop ecx
pop ebx
mov edx,dword ptr [eax+ebx+0x78];
mov edx,dword ptr [eax+edx+0x1c];ImageExportDirectory.AddressofFunctions
add edx,eax
mov ecx,dword ptr [edx+edi*4];從函數地址數組中取值(是偏移)
mov FuncAddr,ecx
add ecx,eax
mov edx,OutputDebug
mov esi,edx
push esi
call ecx;call OutputDebguStringA,可以用DbgView看到字符串'OutputDebugStringA'
jmp retu
search_done:
pop ecx
pop ebx
retu:
xor eax,eax
;ret
}
}
int main()
{
sell();
printf("dMZ:0x%x\n",dMZ);
printf("e_lfanew:0x%x\n",e_lfanew);
printf("dSignature:0x%x\n",dSignature);
printf("dNumberOfSections:0x%x\n",dNumberOfSections);
printf("wSizeOfOptionalHeader:0x%x\n",wSizeOfOptionalHeader);
printf("DataDirExport:0x%x\n",DataDirExport);
printf("SectionVA:0x%x\n",SectionVA);
printf("SectionHeaderPTRD:0x%x\n",SectionHeaderPTRD);
printf("NumberOfNames;0x%x\n",NumberOfNames);
printf("FuncIndex:0x%x,..%d\n",FuncIndex,FuncIndex);
printf("FuncAddr:0x%x\n",FuncAddr);
getchar();
return 0;
}
DbgView的截圖: