PE嵌入模板

编写一段代码,生成一个已经处理过重定位信息,同时所有的内容都在代码段里,并且没有导入表的PE程序,把这个程序嵌入到其他PE的相关位置,能够独立的运行,接下来是整理了2个模板,一个是HelloWorld的,另一个是通用模板LoadLibrary的模板。

开发环境masm32和vs2012,相关环境搭建我之前整理过[ http://blog.csdn.net/u013761036/article/details/52186683 ];

直接C++的话貌似不行,我用vs2015本地创建了一个空的项目,默认优化全开:

还是会有kernel32.dll。

接下来是模板1,功能是所有的东西都在一个独立的模块,弹出对话框,同时处理了全局变量的重定位问题。模板如下[代码是仿照Windows PE 权威指南,但是有些地方已经改过了,书上代码在我本地跑有问题,再获取Kernel32.dll地址的时候并不能成功得到地址。那个函数我已经重写了]:

;----------------------------------------
;补丁代码
;本段代码使用了API函数地址动态获取以及重定位技术
;程序功能:弹出对话框
;作者:Thinker
;开发日期:2017.4.30
;开发测试环境:vs2012+masm32、Win7 X64
;---------------------------------------- .386
.model flat,stdcall
option casemap:none include windows.inc ;注意,此处不静态包含引入任何其他动态链接库,包括Kernell32.dll _ProtoGetProcAddress typedef proto :dword,:dword
_ProtoLoadLibrary typedef proto :dword
_ApiGetProcAddress typedef ptr _ProtoGetProcAddress
_ApiLoadLibrary typedef ptr _ProtoLoadLibrary ;----------------------------------------
;补丁代码中引入的其他动态链接库函数的声明
;---------------------------------------- _ProtoMessageBox typedef proto :dword,:dword,:dword,:dword
_ApiMessageBox typedef ptr _ProtoMessageBox ;被添加到目标文件的代码从这里开始,到APPEND_CODE_END处结束
.code
jmp _NewEntry ;以下内容为两个重要函数名
;几乎所有补丁都必须使用
szGetProcAddr db 'GetProcAddress',0
szLoadLib db 'LoadLibraryA',0 ;----------------------------------------
;补丁代码中其他全局变量的定义
;---------------------------------------- szUser32Dll db 'user32.dll',0
szMessageBox db 'MessageBoxA',0
szHello db 'HelloWorldPE',0
;----------------------------------------
;获取kernel32.dll 的基地址
;---------------------------------------- _getKernelBase proc ;下面是Windows PE权威指南上的代码,获取Kernel32.dll地址失败,无奈我用自己之前的C++代码改了下,测试几次发现可以
;local @dwRet
;pushad
;assume fs:nothing
;mov eax,fs:[30h] ;PEB
;mov eax,[eax+0ch] ;PEB_LDE_DATA
;mov esi,[eax+1ch] ;InInitializationOrderModuleList
;lodsd
;mov eax,[eax+8] ;Kernel32.dll的基地址
;mov @dwRet ,eax
;popad
;mov eax,@dwRet
;ret ;之前写的C++代码改的[http://blog.csdn.net/u013761036/article/details/71006302] local @dwRet
pushad
assume fs:nothing
mov ebx, fs:[30h] ;得到peb结构体的地址
mov ebx, [ebx + 0ch] ;得到Ldr结构体的地址
mov ebx, [ebx + 0ch] ;得到ldr.InLoadOrderModuleList.Flink 第一个模块,当前进程
mov ebx, [ebx] ;得到第二个模块地址 ntdll.dll
mov ebx, [ebx] ;得到第三个模块地址 kernel32.dll
mov ebx, [ebx + 18h] ;得到第三个模块地址(kernel32模块的dllbase)
mov @dwRet, ebx
popad
mov eax,@dwRet
ret
_getKernelBase endp ;----------------------------------------
;获取制定字符串的API函数的调用地址
;入口参数:_hModule 为动态链接库的基地址
; _lpApi为API函数名称首指
;出口参数:eax 位函数在虚拟地址空间中的真实地址
;----------------------------------------
_getApi proc _hModule,_lpApi
local @ret
local @dwLen
pushad
mov @ret,0
;计算API字符串的长度,含最后的0
mov edi,_lpApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpApi
mov @dwLen,ecx ;从PE文件头的数据目录获取导出表地址
mov esi,_hModule
add esi,[esi+3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,_hModule
assume esi:ptr IMAGE_EXPORT_DIRECTORY ;查找符合名称的导出函数名
mov ebx,[esi].AddressOfNames
add ebx,_hModule
xor edx,edx
.repeat
push esi
mov edi,[ebx]
add edi,_hModule
mov esi,_lpApi
mov ecx,@dwLen
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add ebx,4
inc edx
.until edx >= [esi].NumberOfNames
jmp _ret
@@:
;通过API名称索引获取序号索引,再获取地址索引
sub ebx,[esi].AddressOfNames
sub ebx,_hModule
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,_hModule
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,_hModule ;从地址表得到导出函数地址
mov eax,[eax]
add eax,_hModule
mov @ret,eax _ret:
assume esi:nothing
popad
mov eax,@ret
ret
_getApi endp ;----------------------------------------
;补丁功能部分
;传入3个参数
; _kernel :kernel32.dll的基地址
; _getAddr:函数GetProcAddress地址
; _LoadLib:函数LoadLibraryA地址
;----------------------------------------
_patchFun proc _kernel,_getAddr,_loadLib ;----------------------------------------
;补丁代码局部变量定义
;---------------------------------------- local hUser32Base:dword
local _messageBox:_ApiMessageBox pushad ;----------------------------------------
;补丁功能代码,下面例子弹出对话框
;----------------------------------------
;获取user32.dll的基地址
mov eax,offset szUser32Dll
add eax,ebx mov edx,_loadLib
push eax
call edx
mov hUser32Base,eax ;使用GetProcAddress函数的首地址
;传入两个参数调用GetProcAddress函数
;获得MessageBoxA的首地址
mov eax,offset szMessageBox
add eax,ebx mov edx,_getAddr
mov ecx,hUser32Base
push eax
push ecx
call edx
mov _messageBox,eax ;调用函数MessageBox
mov eax,offset szHello
add eax,ebx
mov edx,_messageBox push MB_OK
push NULL
push eax
push NULL
call edx popad
ret _patchFun endp _start proc
local hKernel32Base:dword ;存放kernel32.dll基地址 local _getProcAddress:_ApiGetProcAddress
local _loadLibrary :_ApiLoadLibrary
pushad
;获取kernel32.dll的基地址
lea edx,_getKernelBase
add eax,ebx
call edx
mov hKernel32Base,eax ;从基地址出发搜索GetProcAddress函数的首地址
mov eax,offset szGetProcAddr
add eax,ebx mov edi,hKernel32Base
mov ecx,edi
lea edx,_getApi
add edx,ebx push eax
push ecx
call edx
mov _getProcAddress,eax ;从基地址出发搜索LoadLibraryA函数的首地址
mov eax,offset szLoadLib
add eax,ebx mov edi,hKernel32Base
mov ecx,edi
lea edx,_getApi
add edx,ebx push eax
push ecx
call edx
mov _loadLibrary,eax ;调用补丁代码
lea edx,_patchFun
add edx,ebx push _loadLibrary
push _getProcAddress
push hKernel32Base
call edx popad
ret
_start endp ;EXE文件新的入口地址 _NewEntry:
call @F ;免去重定位
@@:
pop ebx
sub ebx,offset @B invoke _start
jmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh
ret
end _NewEntry

最后的黑体是跳转用的。如果单独跑这个地方可以去掉,不然一条转都崩溃了,通常留着是为了嵌入到别的程序里之后,执行完之后跳转到原来程序入口地址等。

模板1的执行结果如下:

并没有导入表,同时相关字符串也没有存在数据段里:

代码段部分就是全部了,可以拷贝来独立的用。

模板2:和1类似,就是做了一个loadlibrary的模板,这样就和其他注入姿势一样了,只是加载一个dll,然后所有的东西在dll里面写就行了。Dllmain函数被调用的时候记得触发下自己就OK了。模板代码如下[一样书上的获取kernel32.dll代码无效,此处已经修正]。


;----------------------------------------
;补丁代码
;本段代码使用了API函数地址动态获取以及重定位技术
;程序功能:loadlibrary实现通用补丁代码
;作者:Thinker
;开发日期:2017.4.30
;开发测试环境:vs2012+masm32、Win7 X64
;---------------------------------------- .386
.model flat,stdcall
option casemap:none include windows.inc _ProtoLoadLibrary typedef proto :dword
_ApiLoadLibrary typedef ptr _ProtoLoadLibrary ;被添加到目标文件的代码从这里开始,到APPEND_CODE_END处结束
.code
jmp _NewEntry szLoadLib db 'LoadLibraryA',0
szDllName db 'I.dll',0 ;----------------------------------------
;获取kernel32.dll 的基地址
;----------------------------------------
_getKernelBase proc local @dwRet
pushad
assume fs:nothing
mov ebx, fs:[30h] ;得到peb结构体的地址
mov ebx, [ebx + 0ch] ;得到Ldr结构体的地址
mov ebx, [ebx + 0ch] ;得到ldr.InLoadOrderModuleList.Flink 第一个模块,当前进程
mov ebx, [ebx] ;得到第二个模块地址 ntdll.dll
mov ebx, [ebx] ;得到第三个模块地址 kernel32.dll
mov ebx, [ebx + 18h] ;得到第三个模块地址(kernel32模块的dllbase)
mov @dwRet, ebx
popad
mov eax,@dwRet
ret
_getKernelBase endp ;----------------------------------------
;获取制定字符串的API函数的调用地址
;入口参数:_hModule 为动态链接库的基地址
; _lpApi为API函数名称首指
;出口参数:eax 位函数在虚拟地址空间中的真实地址
;----------------------------------------
_getApi proc _hModule,_lpApi
local @ret
local @dwLen
pushad
mov @ret,0
;计算API字符串的长度,含最后的0
mov edi,_lpApi
mov ecx,-1
xor al,al
cld
repnz scasb
mov ecx,edi
sub ecx,_lpApi
mov @dwLen,ecx ;从PE文件头的数据目录获取导出表地址
mov esi,_hModule
add esi,[esi+3ch]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,_hModule
assume esi:ptr IMAGE_EXPORT_DIRECTORY ;查找符合名称的导出函数名
mov ebx,[esi].AddressOfNames
add ebx,_hModule
xor edx,edx
.repeat
push esi
mov edi,[ebx]
add edi,_hModule
mov esi,_lpApi
mov ecx,@dwLen
repz cmpsb
.if ZERO?
pop esi
jmp @F
.endif
pop esi
add ebx,4
inc edx
.until edx >= [esi].NumberOfNames
jmp _ret
@@:
;通过API名称索引获取序号索引,再获取地址索引
sub ebx,[esi].AddressOfNames
sub ebx,_hModule
shr ebx,1
add ebx,[esi].AddressOfNameOrdinals
add ebx,_hModule
movzx eax,word ptr [ebx]
shl eax,2
add eax,[esi].AddressOfFunctions
add eax,_hModule ;从地址表得到导出函数地址
mov eax,[eax]
add eax,_hModule
mov @ret,eax _ret:
assume esi:nothing
popad
mov eax,@ret
ret
_getApi endp _start proc
local hKernel32Base:dword ;存放kernel32.dll基地址
local _loadLibrary :_ApiLoadLibrary
pushad
;获取kernel32.dll的基地址
lea edx,_getKernelBase
add eax,ebx
call edx
mov hKernel32Base,eax ;从基地址出发搜索LoadLibraryA函数的首地址
mov eax,offset szLoadLib
add eax,ebx mov edi,hKernel32Base
mov ecx,edi
lea edx,_getApi
add edx,ebx push eax
push ecx
call edx
mov _loadLibrary,eax ;调用补丁代码 mov eax,offset szDllName
push eax
call _loadLibrary popad
ret
_start endp ;EXE文件新的入口地址 _NewEntry:
call @F ;免去重定位
@@:
pop ebx
sub ebx,offset @B invoke _start
;jmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh
ret
end _NewEntry

运行结果:

代码段大小0x109,学习资料上的是优化到0x80,然而我照着写完MD各种运行不了,而且他里面定义了一堆变量最后根本没用上。获取Kernel32.dll部分的代码也是错的。FK浪费我太多时间调那个汇编代码,后来直接自己改了一个。上面的那个没有采取优化的姿势,需要用的,如果感觉大的话可以进行下汇编代码调整,优化下体积。

以后的PE嵌入通常用的也是这个通用的模板,因为只要通常Loadlibrary就OK了。当然如果想做反弹或者别的,对应的用这个姿势改就行了。目标就是不要有导入表,记得处理重定位,函数用到的数据记得是在代码段,不是放在数据段里面。

Windows PE变形练手2-开发一套自己的PE嵌入模板的更多相关文章

  1. Windows PE变形练手1-用PE自己的机器码修改自己的逻辑

    PE变形练手1-用PE自己的机器码修改自己的逻辑 就是找一个PE文件,用自己的部分代码部分覆盖或者而修改自己另一个代码部分的补丁姿势(现实中使用很少,极少数破解可以用到.这次例子目的是了解PE). 第 ...

  2. Windows PE变形练手3-把通用模板机器码直接覆盖目标PE

    把通用模板机器码直覆盖目标PE 这个地方真是尝试了好久,遇到很多坑点,Win PE那本书上的东西有点不够,也就直接写书上的例子会发现很多地方不是说的那样,里面提供的信息太少了,就比如里面并没有提被注入 ...

  3. Windows API初练手 -- 疯狂写文件代码

    警告:恶作剧软件,慎用!仅供初学者研究代码所用!!! 提示:默认文件创建目录在"D:\test",如果需要使用的话请自行更改目录. 1. Windows API 版本 (调用系统函 ...

  4. Xamarin入门,开发一个简单的练手APP

    之前周末用Xamarin练手做了个简单APP,没有啥逻辑基本就是个界面架子,MVVM的简单使用,还有Binding,Command的简单使用,还有一个稍微复杂点两个界面交互处理(子页面新增后关闭,父页 ...

  5. NEXYS 3开发板练手--LED与数码管时钟

    做科研的时候从学校拿到一块基于Xilinx公司Spartan-6主芯片的FPGA开发板,因为之前一直在用Altera公司的FPGA,一开始接触它还真有点不太习惯.但毕竟核心的东西还是不会变的,于是按照 ...

  6. Windows PE 第十二章 PE变形技术

    PE变形技术 这章东西太多,太细了.这里我只记录了一些重点概念.为后面学习做铺垫. PE变形:改变PE结构之后,PE加载器依然可以成功加载运行我们的程序. 一 变形常用技术: 结构重叠技术.空间调整技 ...

  7. web前端学习部落22群分享给需要前端练手项目

    前端学习还是很有趣的,可以较快的上手然后自己开发一些好玩的项目来练手,网上也可以一抓一大把关于前端开发的小项目,可是还是有新手在学习的时候不知道可以做什么,以及怎么做,因此,就整理了一些前端项目教程, ...

  8. Cocos2d-x 3.X手游开发实例详解

    Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...

  9. webpack练手项目之easySlide(三):commonChunks(转)

    Hello,大家好. 在之前两篇文章中: webpack练手项目之easySlide(一):初探webpack webpack练手项目之easySlide(二):代码分割 与大家分享了webpack的 ...

随机推荐

  1. [源码分析] 消息队列 Kombu 之 Consumer

    [源码分析] 消息队列 Kombu 之 Consumer 目录 [源码分析] 消息队列 Kombu 之 Consumer 0x00 摘要 0x01 综述功能 0x02 示例代码 0x03 定义 3.1 ...

  2. FreeBSD——艺术、科学、哲学概论

    FreeBSD--艺术.科学.哲学概论→→→→→概论: 信息都有一定的时效性.那么现在是什么时间?现在已经发布了 FreeBSD 12.2,距离下一个版本 13.0 还有约 4 个月. 『约定』 使用 ...

  3. Java实现解压缩文件和文件夹

    一 前言 项目开发中,总会遇到解压缩文件的时候.比如,用户下载多个文件时,服务端可以将多个文件压缩成一个文件(例如xx.zip或xx.rar).用户上传资料时,允许上传压缩文件,服务端进行解压读取每一 ...

  4. c语言链表从本地文件中读取和写入数据

    1 typedef struct Data{ 2 40 char *name; 3 41 char *IDCARD; 4 42 char *job_id; 5 43 char *length; 6 4 ...

  5. SparkSQL中产生笛卡尔积的几种典型场景以及处理策略

    [前言:如果你经常使用Spark SQL进行数据的处理分析,那么对笛卡尔积的危害性一定不陌生,比如大量占用集群资源导致其他任务无法正常执行,甚至导致节点宕机.那么都有哪些情况会产生笛卡尔积,以及如何事 ...

  6. Hdu 4821 (字符串hash+map)

    题目链接https://vjudge.net/problem/HDU-4821 题意:给定字符串S ,询问用几个子串满足 : 1.长度为n*len  . 2. n个子串都不相同. 题解:倒序hash将 ...

  7. js_笔记_8月7日记录_活动对象_作用域链_按值传递

    活动对象:简单说就是这个函数的参数和显示声明的变量或函数. 函数内接受的参数实际是创建了一个局部变量:[形参名] = [传进来的值],js的函数传参只传值. 作用域链:执行流进入一个函数,会先创建出作 ...

  8. 获取执行计划之Autotrace

    Autotrace 简介 AUTOTRACE是一项SQL*Plus功能,自动跟踪为SQL语句生成一个执行计划并且提供与该语句的处理有关的统计. AUTOTRACE的好处是您不必设置跟踪文件的格式,并且 ...

  9. oo第四单元暨课程总结

    第四单元架构设计总结 第一次作业 单独写了MyUmlClass.MyUmlInterface.MyUmlOperation三个类对应UML中相应元素,在UML图中这几个元素包含一些下级元素,如Clas ...

  10. malloc 函数分析 glibc2.23

    malloc 函数详解 本篇主要是参考了glibc 2.23的源码 首先我们来看看malloc函数的执行流程. strong_alias (__libc_malloc, __malloc) stron ...