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地址的时候并不能成功得到地址。那个函数我已经重写了]:

  1. ;----------------------------------------
  2. ;补丁代码
  3. ;本段代码使用了API函数地址动态获取以及重定位技术
  4. ;程序功能:弹出对话框
  5. ;作者:Thinker
  6. ;开发日期:2017.4.30
  7. ;开发测试环境:vs2012+masm32Win7 X64
  8. ;----------------------------------------
  9. .386
  10. .model flat,stdcall
  11. option casemap:none
  12. include windows.inc
  13. ;注意,此处不静态包含引入任何其他动态链接库,包括Kernell32.dll
  14. _ProtoGetProcAddress typedef proto :dword,:dword
  15. _ProtoLoadLibrary typedef proto :dword
  16. _ApiGetProcAddress typedef ptr _ProtoGetProcAddress
  17. _ApiLoadLibrary typedef ptr _ProtoLoadLibrary
  18. ;----------------------------------------
  19. ;补丁代码中引入的其他动态链接库函数的声明
  20. ;----------------------------------------
  21. _ProtoMessageBox typedef proto :dword,:dword,:dword,:dword
  22. _ApiMessageBox typedef ptr _ProtoMessageBox
  23. ;被添加到目标文件的代码从这里开始,到APPEND_CODE_END处结束
  24. .code
  25. jmp _NewEntry
  26. ;以下内容为两个重要函数名
  27. ;几乎所有补丁都必须使用
  28. szGetProcAddr db 'GetProcAddress',0
  29. szLoadLib db 'LoadLibraryA',0
  30. ;----------------------------------------
  31. ;补丁代码中其他全局变量的定义
  32. ;----------------------------------------
  33. szUser32Dll db 'user32.dll',0
  34. szMessageBox db 'MessageBoxA',0
  35. szHello db 'HelloWorldPE',0
  36. ;----------------------------------------
  37. ;获取kernel32.dll 的基地址
  38. ;----------------------------------------
  39. _getKernelBase proc
  40. ;下面是Windows PE权威指南上的代码,获取Kernel32.dll地址失败,无奈我用自己之前的C++代码改了下,测试几次发现可以
  41. ;local @dwRet
  42. ;pushad
  43. ;assume fs:nothing
  44. ;mov eax,fs:[30h] ;PEB
  45. ;mov eax,[eax+0ch] ;PEB_LDE_DATA
  46. ;mov esi,[eax+1ch] ;InInitializationOrderModuleList
  47. ;lodsd
  48. ;mov eax,[eax+8] ;Kernel32.dll的基地址
  49. ;mov @dwRet ,eax
  50. ;popad
  51. ;mov eax,@dwRet
  52. ;ret
  53. ;之前写的C++代码改的[http://blog.csdn.net/u013761036/article/details/71006302]
  54. local @dwRet
  55. pushad
  56. assume fs:nothing
  57. mov ebx, fs:[30h] ;得到peb结构体的地址
  58. mov ebx, [ebx + 0ch] ;得到Ldr结构体的地址
  59. mov ebx, [ebx + 0ch] ;得到ldr.InLoadOrderModuleList.Flink 第一个模块,当前进程
  60. mov ebx, [ebx] ;得到第二个模块地址 ntdll.dll
  61. mov ebx, [ebx] ;得到第三个模块地址 kernel32.dll
  62. mov ebx, [ebx + 18h] ;得到第三个模块地址(kernel32模块的dllbase)
  63. mov @dwRet, ebx
  64. popad
  65. mov eax,@dwRet
  66. ret
  67. _getKernelBase endp
  68. ;----------------------------------------
  69. ;获取制定字符串的API函数的调用地址
  70. ;入口参数:_hModule 为动态链接库的基地址
  71. ; _lpApiAPI函数名称首指
  72. ;出口参数:eax 位函数在虚拟地址空间中的真实地址
  73. ;----------------------------------------
  74. _getApi proc _hModule,_lpApi
  75. local @ret
  76. local @dwLen
  77. pushad
  78. mov @ret,0
  79. ;计算API字符串的长度,含最后的0
  80. mov edi,_lpApi
  81. mov ecx,-1
  82. xor al,al
  83. cld
  84. repnz scasb
  85. mov ecx,edi
  86. sub ecx,_lpApi
  87. mov @dwLen,ecx
  88. ;从PE文件头的数据目录获取导出表地址
  89. mov esi,_hModule
  90. add esi,[esi+3ch]
  91. assume esi:ptr IMAGE_NT_HEADERS
  92. mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
  93. add esi,_hModule
  94. assume esi:ptr IMAGE_EXPORT_DIRECTORY
  95. ;查找符合名称的导出函数名
  96. mov ebx,[esi].AddressOfNames
  97. add ebx,_hModule
  98. xor edx,edx
  99. .repeat
  100. push esi
  101. mov edi,[ebx]
  102. add edi,_hModule
  103. mov esi,_lpApi
  104. mov ecx,@dwLen
  105. repz cmpsb
  106. .if ZERO?
  107. pop esi
  108. jmp @F
  109. .endif
  110. pop esi
  111. add ebx,4
  112. inc edx
  113. .until edx >= [esi].NumberOfNames
  114. jmp _ret
  115. @@:
  116. ;通过API名称索引获取序号索引,再获取地址索引
  117. sub ebx,[esi].AddressOfNames
  118. sub ebx,_hModule
  119. shr ebx,1
  120. add ebx,[esi].AddressOfNameOrdinals
  121. add ebx,_hModule
  122. movzx eax,word ptr [ebx]
  123. shl eax,2
  124. add eax,[esi].AddressOfFunctions
  125. add eax,_hModule
  126. ;从地址表得到导出函数地址
  127. mov eax,[eax]
  128. add eax,_hModule
  129. mov @ret,eax
  130. _ret:
  131. assume esi:nothing
  132. popad
  133. mov eax,@ret
  134. ret
  135. _getApi endp
  136. ;----------------------------------------
  137. ;补丁功能部分
  138. ;传入3个参数
  139. ; _kernel :kernel32.dll的基地址
  140. ; _getAddr:函数GetProcAddress地址
  141. ; _LoadLib:函数LoadLibraryA地址
  142. ;----------------------------------------
  143. _patchFun proc _kernel,_getAddr,_loadLib
  144. ;----------------------------------------
  145. ;补丁代码局部变量定义
  146. ;----------------------------------------
  147. local hUser32Base:dword
  148. local _messageBox:_ApiMessageBox
  149. pushad
  150. ;----------------------------------------
  151. ;补丁功能代码,下面例子弹出对话框
  152. ;----------------------------------------
  153. ;获取user32.dll的基地址
  154. mov eax,offset szUser32Dll
  155. add eax,ebx
  156. mov edx,_loadLib
  157. push eax
  158. call edx
  159. mov hUser32Base,eax
  160. ;使用GetProcAddress函数的首地址
  161. ;传入两个参数调用GetProcAddress函数
  162. ;获得MessageBoxA的首地址
  163. mov eax,offset szMessageBox
  164. add eax,ebx
  165. mov edx,_getAddr
  166. mov ecx,hUser32Base
  167. push eax
  168. push ecx
  169. call edx
  170. mov _messageBox,eax
  171. ;调用函数MessageBox
  172. mov eax,offset szHello
  173. add eax,ebx
  174. mov edx,_messageBox
  175. push MB_OK
  176. push NULL
  177. push eax
  178. push NULL
  179. call edx
  180. popad
  181. ret
  182. _patchFun endp
  183. _start proc
  184. local hKernel32Base:dword ;存放kernel32.dll基地址
  185. local _getProcAddress:_ApiGetProcAddress
  186. local _loadLibrary :_ApiLoadLibrary
  187. pushad
  188. ;获取kernel32.dll的基地址
  189. lea edx,_getKernelBase
  190. add eax,ebx
  191. call edx
  192. mov hKernel32Base,eax
  193. ;从基地址出发搜索GetProcAddress函数的首地址
  194. mov eax,offset szGetProcAddr
  195. add eax,ebx
  196. mov edi,hKernel32Base
  197. mov ecx,edi
  198. lea edx,_getApi
  199. add edx,ebx
  200. push eax
  201. push ecx
  202. call edx
  203. mov _getProcAddress,eax
  204. ;从基地址出发搜索LoadLibraryA函数的首地址
  205. mov eax,offset szLoadLib
  206. add eax,ebx
  207. mov edi,hKernel32Base
  208. mov ecx,edi
  209. lea edx,_getApi
  210. add edx,ebx
  211. push eax
  212. push ecx
  213. call edx
  214. mov _loadLibrary,eax
  215. ;调用补丁代码
  216. lea edx,_patchFun
  217. add edx,ebx
  218. push _loadLibrary
  219. push _getProcAddress
  220. push hKernel32Base
  221. call edx
  222. popad
  223. ret
  224. _start endp
  225. ;EXE文件新的入口地址
  226. _NewEntry:
  227. call @F ;免去重定位
  228. @@:
  229. pop ebx
  230. sub ebx,offset @B
  231. invoke _start
  232. jmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh
  233. ret
  234. end _NewEntry

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

模板1的执行结果如下:

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

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

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


  1. ;----------------------------------------
  2. ;补丁代码
  3. ;本段代码使用了API函数地址动态获取以及重定位技术
  4. ;程序功能:loadlibrary实现通用补丁代码
  5. ;作者:Thinker
  6. ;开发日期:2017.4.30
  7. ;开发测试环境:vs2012+masm32Win7 X64
  8. ;----------------------------------------
  9. .386
  10. .model flat,stdcall
  11. option casemap:none
  12. include windows.inc
  13. _ProtoLoadLibrary typedef proto :dword
  14. _ApiLoadLibrary typedef ptr _ProtoLoadLibrary
  15. ;被添加到目标文件的代码从这里开始,到APPEND_CODE_END处结束
  16. .code
  17. jmp _NewEntry
  18. szLoadLib db 'LoadLibraryA',0
  19. szDllName db 'I.dll',0
  20. ;----------------------------------------
  21. ;获取kernel32.dll 的基地址
  22. ;----------------------------------------
  23. _getKernelBase proc
  24. local @dwRet
  25. pushad
  26. assume fs:nothing
  27. mov ebx, fs:[30h] ;得到peb结构体的地址
  28. mov ebx, [ebx + 0ch] ;得到Ldr结构体的地址
  29. mov ebx, [ebx + 0ch] ;得到ldr.InLoadOrderModuleList.Flink 第一个模块,当前进程
  30. mov ebx, [ebx] ;得到第二个模块地址 ntdll.dll
  31. mov ebx, [ebx] ;得到第三个模块地址 kernel32.dll
  32. mov ebx, [ebx + 18h] ;得到第三个模块地址(kernel32模块的dllbase)
  33. mov @dwRet, ebx
  34. popad
  35. mov eax,@dwRet
  36. ret
  37. _getKernelBase endp
  38. ;----------------------------------------
  39. ;获取制定字符串的API函数的调用地址
  40. ;入口参数:_hModule 为动态链接库的基地址
  41. ; _lpApiAPI函数名称首指
  42. ;出口参数:eax 位函数在虚拟地址空间中的真实地址
  43. ;----------------------------------------
  44. _getApi proc _hModule,_lpApi
  45. local @ret
  46. local @dwLen
  47. pushad
  48. mov @ret,0
  49. ;计算API字符串的长度,含最后的0
  50. mov edi,_lpApi
  51. mov ecx,-1
  52. xor al,al
  53. cld
  54. repnz scasb
  55. mov ecx,edi
  56. sub ecx,_lpApi
  57. mov @dwLen,ecx
  58. ;从PE文件头的数据目录获取导出表地址
  59. mov esi,_hModule
  60. add esi,[esi+3ch]
  61. assume esi:ptr IMAGE_NT_HEADERS
  62. mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
  63. add esi,_hModule
  64. assume esi:ptr IMAGE_EXPORT_DIRECTORY
  65. ;查找符合名称的导出函数名
  66. mov ebx,[esi].AddressOfNames
  67. add ebx,_hModule
  68. xor edx,edx
  69. .repeat
  70. push esi
  71. mov edi,[ebx]
  72. add edi,_hModule
  73. mov esi,_lpApi
  74. mov ecx,@dwLen
  75. repz cmpsb
  76. .if ZERO?
  77. pop esi
  78. jmp @F
  79. .endif
  80. pop esi
  81. add ebx,4
  82. inc edx
  83. .until edx >= [esi].NumberOfNames
  84. jmp _ret
  85. @@:
  86. ;通过API名称索引获取序号索引,再获取地址索引
  87. sub ebx,[esi].AddressOfNames
  88. sub ebx,_hModule
  89. shr ebx,1
  90. add ebx,[esi].AddressOfNameOrdinals
  91. add ebx,_hModule
  92. movzx eax,word ptr [ebx]
  93. shl eax,2
  94. add eax,[esi].AddressOfFunctions
  95. add eax,_hModule
  96. ;从地址表得到导出函数地址
  97. mov eax,[eax]
  98. add eax,_hModule
  99. mov @ret,eax
  100. _ret:
  101. assume esi:nothing
  102. popad
  103. mov eax,@ret
  104. ret
  105. _getApi endp
  106. _start proc
  107. local hKernel32Base:dword ;存放kernel32.dll基地址
  108. local _loadLibrary :_ApiLoadLibrary
  109. pushad
  110. ;获取kernel32.dll的基地址
  111. lea edx,_getKernelBase
  112. add eax,ebx
  113. call edx
  114. mov hKernel32Base,eax
  115. ;从基地址出发搜索LoadLibraryA函数的首地址
  116. mov eax,offset szLoadLib
  117. add eax,ebx
  118. mov edi,hKernel32Base
  119. mov ecx,edi
  120. lea edx,_getApi
  121. add edx,ebx
  122. push eax
  123. push ecx
  124. call edx
  125. mov _loadLibrary,eax
  126. ;调用补丁代码
  127. mov eax,offset szDllName
  128. push eax
  129. call _loadLibrary
  130. popad
  131. ret
  132. _start endp
  133. ;EXE文件新的入口地址
  134. _NewEntry:
  135. call @F ;免去重定位
  136. @@:
  137. pop ebx
  138. sub ebx,offset @B
  139. invoke _start
  140. ;jmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh
  141. ret
  142. 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. Linux发行版及其目标用户

    1.Debian Debian 众所周知,是Deepin,Ubuntu和Mint等流行Linux发行版的母亲,这些发行版提供了可靠的性能,稳定性和无与伦比的用户体验.最新的稳定发行版是Debian 1 ...

  2. mongodb为什么比mysql效率高

    首先是内存映射机制,数据不是持久化到存储设备中的,而是暂时存储在内存中,这就提高了在IO上效率以及操作系统对存储介质之间的性能损耗.(毕竟内存读取最快) 其次,NoSQL并不是不使用sql,只是不使用 ...

  3. Codeforces Round #545 B. Circus

    题面: 传送门 题目描述: 马戏团中一共有N个人(N是偶数),有的人会扮演小丑,有的人会表演杂技.给出每个人会什么,然后按照下列规则把这些人分成两组: 每个人只能在其中一组 两个组的人数相等(也就是把 ...

  4. API管理工具

    开源的api文档管理系统 api文档 php 在项目中,需要协同开发,所以会写许多API文档给其他同事,以前都是写一个简单的TXT文本或Word文档,口口相传,这种方式比较老土了,所以,需要有个api ...

  5. 主成分分析 | Principal Components Analysis | PCA

    理论 仅仅使用基本的线性代数知识,就可以推导出一种简单的机器学习算法,主成分分析(Principal Components Analysis, PCA). 假设有 $m$ 个点的集合:$\left\{ ...

  6. Tomcat详解系列(1) - 如何设计一个简单的web容器

    Tomcat - 如何设计一个简单的web容器 在学习Tomcat前,很多人先入为主的对它的认知是巨复杂的:所以第一步,在学习它之前,要打破这种观念,我们通过学习如何设计一个最基本的web容器来看它需 ...

  7. P1047_校门外的树(JAVA语言)

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米. 我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置: 数轴上的每个整数点,即0,1,2,-,L都种 ...

  8. 攻防世界 reverse 进阶 easyre-153

    easyre-153 查壳: upx壳 脱壳: 1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 int ...

  9. 一种3位sar adc仿真验证

    3位sar adc采用下图的电容阵列,电路如下图:所有电容的正端(也称为上极板)与比较器的同相端连接,比较器反相端接gnd,其工作过程进行大致分析见之前的文章<一种3位sar adc工作过程推导 ...

  10. Android Studio 待看博文

    •前言 学习过程中找到的一些好的博文,有些可能当时就看完了并解决了我的问题,有些可能需要好几天的事件才能消化. 特此记录,方便查阅. •CSDN 给新人的一些基础常识 TextView的文字长度测量及 ...