欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 《Windows PE》6.3 无导入表和重定位表PE文件

《Windows PE》6.3 无导入表和重定位表PE文件

2025/4/19 12:52:09 来源:https://blog.csdn.net/bcdaren/article/details/142933298  浏览:    关键词:《Windows PE》6.3 无导入表和重定位表PE文件

本节我们将演示一个无导入表、无重定位表,并且只有一个.text节区的汇编代码程序。

本节必须掌握的知识点:

        汇编代码重定位

6.3.1 汇编代码重定位

实验四十四:模拟地址重定位

将第一章中的示例程序HelloWorld汇编程序改成一个无重定位、无导入表的程序。

 注意

       1.在Windows 64位系统环境编译时,默认会有重定位节区,因此改为在Windows XP系统环境下编译。

2.HelloWorld1.exe编译生成后,需要将.text节属性改为可读可写可执行60000020改为E0000020。

●第一步:编写汇编代码

1.HelloWorld.asm(略)

2.HelloWorld1.asm

;FileName:HelloWorld1.asm;实验44:无导入表、无重定位表程序;by:bcdaren;2021.01.06;=======================================.386.model flat,stdcalloption casemap:noneinclude    windows.inc;CPUX64 = 1  ;X64 masm64编译;CPUX86= 1   ;x86;声明函数BCGetProcAddress      typedef proto :dword,:dword  ;声明函数引用  ApiGetProcAddress     typedef ptr BCGetProcAddress BCLoadLibrary          typedef proto :dwordApiLoadLibrary           typedef ptr BCLoadLibraryBCMessageBoxA       typedef proto :dword,:dword,:dword,:dwordApiMessageBoxA       typedef ptr BCMessageBoxA;代码段.codeszText                   db  "Hello,welcome to PE!",0szGetProcAddress       db  "GetProcAddress",0szLoadLibrary          db  "LoadLibraryA",0szMessageBox           db  "MessageBoxA",0user32_DLL              db  "user32.dll",0,0;定义函数getProcAddress           ApiGetProcAddress     ?            loadLibrary               ApiLoadLibrary          ?messageBox             ApiMessageBoxA     ?hKernel32Base          dd  ?hUser32Base            dd  ?lpGetProcAddress      dd  ?lpLoadLibrary          dd  ?;------------------------------------; 根据PEB 获取kernel32.dll的基地址;------------------------------------getKernelBase  procIFDEF CPUX64assume gs:nothingmov rax, gs:[60h]          ;获取PEB所在地址mov rax, [rax + 18h]     ; LDRmov rax, [rax + 30h]     ; InLoadOrderModuleList.Blink,mov rax, [rax]        ;[_LDR_MODULE.InLoadOrderModuleList].Blink kernelbase.dllmov rax, [rax]        ; [_LDR_MODULE.InLoadOrderModuleList].Blink kernel32.dllmov rax, [rax + 10h]     ; [_LDR_MODULE.InLoadOrderModuleList]. BaseAddressELSE  assume fs:nothingmov eax,fs:[30h]           ;获取PEB所在地址mov eax,[eax + 0ch]     ;获取PEB_LDR_DATA 结构指针mov eax,[eax + 0ch]     ;InLoadOrderModuleListmov eax,[eax]        ;[_LDR_MODULE.InLoadOrderModuleList].Blink kernelbase.dllmov eax,[eax]        ;[_LDR_MODULE.InLoadOrderModuleList].Blink kernel32.dllmov eax,[eax + 18h]     ;[_LDR_MODULE.InLoadOrderModuleList]. BaseAddressENDIFretgetKernelBase  endp  ;-------------------------------; 获取指定字符串的API函数的调用地址; 入口参数:_hModule为动态链接库的基址;           _lpApi为API函数名的首址; 出口参数:eax为函数在虚拟地址空间中的真实地址;-------------------------------getApi proc _hModule,_lpApilocal @retlocal @dwLenpushadmov @ret,0;计算API字符串的长度,含最后的零mov edi,_lpApimov ecx,-1xor al,alcldrepnz scasbmov ecx,edisub ecx,_lpApimov @dwLen,ecx;从pe文件头的数据目录获取导出表地址mov esi,_hModuleadd esi,[esi+3ch]IFDEF CPUX64assume esi:ptr IMAGE_NT_HEADERS64ELSEassume esi:ptr IMAGE_NT_HEADERS32ENDIFmov esi,[esi].OptionalHeader.DataDirectory.VirtualAddressadd esi,_hModuleassume esi:ptr IMAGE_EXPORT_DIRECTORY;查找符合名称的导出函数名mov ebx,[esi].AddressOfNamesadd ebx,_hModulexor edx,edx.repeatpush esimov edi,[ebx]add edi,_hModulemov esi,_lpApimov ecx,@dwLenrepz cmpsb.if ZERO?pop esijmp @F.endifpop esiadd ebx,4inc edx.until edx>=[esi].NumberOfNamesjmp _ret@@:;通过API名称索引获取序号索引再获取地址索引sub ebx,[esi].AddressOfNamessub ebx,_hModuleshr ebx,1add ebx,[esi].AddressOfNameOrdinalsadd ebx,_hModulemovzx eax,word ptr [ebx]shl eax,2add eax,[esi].AddressOfFunctionsadd eax,_hModule;从地址表得到导出函数的地址mov eax,[eax]add eax,_hModulemov @ret,eax_ret:assume esi:nothingpopadmov eax,@retretgetApi endp;==========================================start:   ;取当前函数的堆栈栈顶值mov eax,dword ptr [esp]push eaxcall @F   ; 免去重定位@@:pop ebxsub ebx,offset @Bpop eax;获取kernel32.dll的基地址invoke getKernelBasemov [ebx+offset hKernel32Base],eax;从基地址出发搜索GetProcAddress函数的首址mov eax,offset szGetProcAddressadd eax,ebxmov edi,offset hKernel32Basemov ecx,[ebx+edi]invoke getApi,ecx,eaxmov [ebx+offset lpGetProcAddress],eax;为函数引用赋值 GetProcAddressmov [ebx+offset getProcAddress],eax  ;使用GetProcAddress函数的首址;传入两个参数调用GetProcAddress函数,获得LoadLibraryA的首址mov eax,offset szLoadLibraryadd eax,ebxmov edi,offset hKernel32Basemov ecx,[ebx+edi]mov edx,offset getProcAddressadd edx,ebx;模仿调用 invoke GetProcAddress,hKernel32Base,addr szLoadLibpush eaxpush ecxcall dword ptr [edx]  mov [ebx+offset loadLibrary],eax;使用LoadLibrary获取user32.dll的基地址mov eax,offset user32_DLLadd eax,ebxmov edi,offset loadLibrarymov edx,[ebx+edi]push eaxcall edx   ; invoke LoadLibraryA,addr _loadLibrarymov [ebx+offset hUser32Base],eax;使用GetProcAddress函数的首址,获得函数MessageBoxA的首址mov eax,offset szMessageBoxadd eax,ebxmov edi,offset hUser32Basemov ecx,[ebx+edi]mov edx,offset getProcAddressadd edx,ebx;模仿调用 invoke GetProcAddress,hUser32Base,addr szMessageBoxpush eaxpush ecxcall dword ptr [edx]  mov [ebx+offset messageBox],eax;调用函数MessageBoxAmov eax,offset szTextadd eax,ebxmov edx,offset messageBoxadd edx,ebx;模仿调用 invoke MessageBoxA,NULL,addr szText,NULL,MB_OK   push MB_OKpush NULLpush eaxpush NULLcall dword ptr [edx]  retend start

makefile文件:

# makefile文件# 宏定义NAME = HelloWorld1EXE = $(NAME).exe                           #输出文件OBJS = $(NAME).obj                          #目标文件ML_FLAG = /c /coff                           #编译选项LINK_FLAG = /subsystem:windows /FIXED:NO #链接选项# 定义依赖关系和执行命令$(EXE):$(OBJS)link $(LINK_FLAG) $(OBJS)# 定义汇编编译和资源编译默认规则.asm.obj:ml $(ML_FLAG) $<.rc.res:rc $<# 清除临时文件clean:del *.objdel *.res

      

通过查看输出结果可以得知:HelloWorld1.exe只有一个代码段,没有.data节区,没有导入表,也没有导出表和重定位的信息。为了免去导入表、数据段和重定位信息,

●第二步:修改基址

将上述两个程序分别创建一个副本HelloWorld_1.exe和HelloWorld1_1.exe,副本基址0x00400000修改为0x00800000,

其效果可以在其副本中查看,运行它们的副本HelloWorld_1.exe和HelloWorld1_1.exe,有一个可以运行,一个不可以运行。能运行的当然就是使用了重定位技术的HelloWorld1_1.exe。

热搜词