主要是为了练习一下汇编语言编成和pe文件结构。
#include
#include
//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的截图: