打造DLL内存加载引擎学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题

首先看下我们内存加载引擎的流程。

1. 申请一段大小为dll映射内存后的映像大小的内存空间。

2. 移动各个区段的数据到申请的内存。

2. 修复引入表结构的地址表。

4. 通过重定位结构修复需要重定位的地址。

5. 调用DllMain入口点

流程解析:

  1. pe结构中nt header结构当中的ImageSize存放的是我们整个文件映射到内存后的映像大小,这个大小是经过对齐的, 读取这个成员值,来申请内存空间,内存空间的属性为“可读可写可执行”,VirtualAlloc来申请。
  2. 读取各个节表结构的各区段的物理偏移和物理大小,然后移动各区段数据到节表结构对应的的内存空间中(注意:实际上就是将节表结构的VirtualAddress + 申请的内存空间地址),移动的大小则为我们物理大小.
  3. 修复导入表结构的地址表。其实就是修复导入表结构FirstThunk指向的地址表,因为我们的程序api调用的也是FirstThunk所指向的地址表成员。程序在未加载之前FirstThunk指向的地址表成员都指向的是一个IMAGE_IMPORT_BY_NAME结构,当加载后这个地址表的成员都被替换成相应的函数地址。所以处理导入表过程函数可以直接读取FirstThunk来取得相应的引入函数名称及序号等,没必要读取OriginalFirstThunk来读取.
  4. 通过重定位结构修复需要重定位的地址,连接器在链接可执行程序的时候会将需要重定位的偏移存放到一个结构中,这样pe loader读取重定位结构就可以定位到需要重定位的地址。
  5. 压入参数, 取得入口点rva+申请目标空间地址然后call调用即可

代码:

 .386
02.    .model flat, stdcall
03.    option casemap:none
04.
05.include windows.inc
06.include user32.inc
07.include kernel32.inc
08.includelib user32.lib
09.includelib kernel32.lib
10.
11.pushad_eax equ 1ch
12.
13.    .data
14.
15.szFileName  db ‘test.dll‘, 0
16.hFile       dd 0
17.hMap        dd 0
18.
19.    .code
20.
21.Entry:
22.    invoke CreateFile, addr szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, \
23.        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
24.    cmp eax, INVALID_HANDLE_VALUE
25.    je _Ret
26.    mov hFile, eax
27.    invoke CreateFileMapping, eax, NULL, PAGE_READONLY, 0, 0, NULL
28.    .if eax == NULL
29.        invoke CloseHandle, hFile
30.        jmp _Ret
31.    .endif
32.    mov hMap, eax
33.    invoke MapViewOfFile, eax, FILE_MAP_READ, 0, 0, 0
34.    .if eax == NULL
35.        invoke CloseHandle, hMap
36.        invoke CloseHandle, hFile
37.        jmp _Ret
38.    .endif
39.    push eax
40.    call DllMemLoad
41.
42._Ret:
43.    ret
44.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
45.; dll内存加载函数
46.; Arguments:
47.;   [esp]           - return address
48.;   [esp + 4 * 1]       - pDllMemory
49.; Return Value:
50.;   eax =
51.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
52.DllMemLoad:
53.    pushad
54.    mov ebx, [esp + 4 * 8 + 4]          ; ebx = pDllMemory
55.    cmp word ptr [ebx], ‘ZM‘
56.    jnz _RetFalse
57.
58.    push ebx
59.
60.    mov edi, ebx                    ; edi = Dos Header
61.    add edi, [edi + 3ch]                ; edi = NT Header
62.    cmp word ptr [edi], ‘EP‘
63.    jnz _RetFalse
64.
65.    invoke VirtualAlloc, 0, [edi + 50h], MEM_COMMIT, PAGE_EXECUTE_READWRITE
66.    test eax, eax
67.    je _RetFalse
68.    xchg eax, ebp                   ; ebp = lpMemroy
69.
70.    lea esi, [edi + 14h]
71.    xor eax, eax
72.    lodsw                       ; eax = IMAGE_OPTIONAL_HEADER size
73.    lea esi, [esi + 2 + eax]            ; esi -> section table
74.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
75.; 移动节到分配的内存
76.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
77.    movzx ecx, word ptr [edi + 06h]         ; ecx = section num
78.
79._MoveSection:
80.    push ecx
81.    mov edx, [esi + 14h]                ; edx = physical offset
82.    add edx, [esp + 4]              ; [esp + 4] = pDllMemory, edx = source section va
83.    mov eax, [esi + 0ch]                ; eax = VirtualAddress
84.    add eax, ebp                    ; ebp = lpMemory, eax = dest section va
85.    invoke RtlMoveMemory, eax, edx, dword ptr [esi + 10h]
86.    add esi, 28h                    ; esi -> next section
87.    pop ecx
88.    loop _MoveSection
89.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
90.; 处理导入段
91.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
92.    mov edx, ebp                    ; edx = lpMemory
93.    mov eax, edi                    ; eax = NT Header
94.    call InitImport
95.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
96.; 处理重定位
97.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
98.    mov edx, ebp                    ; edx = lpMemory
99.    mov eax, edi                    ; eax = NT Header
100.    call InitFixups
101.
102.    mov edx, [edi + 28h]                ; edx = EntryPoint RVA
103.    add edx, ebp                    ; ebp = lpMemory, edx = EntryPoint VA
104.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
105.; DllMain
106.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
107.    push 0
108.    push 1
109.    push ebp
110.    call edx                    ; call DllMain
111.
112._RetTrue:
113.    pop ecx
114.    push ebp
115.    pop dword ptr [esp + pushad_eax]        ; eax = lpMemory
116.    popad
117.    ret 4
118.
119._RetFalse:
120.    popad
121.    xor eax, eax
122.    ret 4
123.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
124.; 初始化导入表函数
125.; Arguments:
126.;   [esp]           - return address
127.;   eax         - NT Header
128.;   edx         - Alloc mem base
129.; Return Value:
130.;   eax = true or eax = false
131.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
132.InitImport:
133.    pushad
134.    push edx                    ; [esp] = alloc mem base
135.    mov edi, [eax + 80h]                ; edi = Import RVA
136.    add edi, edx                    ; edi = Import VA
137.
138._NextImport:
139.    cmp dword ptr [edi + 0ch], 0            ; [edi + 0ch] = Name
140.    jz _II_RetTrue
141.    mov edx, [edi + 0ch]                ; edx = Name
142.    add edx, [esp]                  ; edx = import dll name string
143.    invoke LoadLibrary, edx
144.    test eax, eax
145.    jz _II_RetFalse
146.    xchg eax, ebx                   ; ebx = load dll base
147.
148.    mov esi, [edi + 10h]
149.    add esi, [esp]                  ; esi = FirstThunk
150.    cld
151.
152._NextIat:
153.    lodsd
154.    test eax, eax
155.    je _Next
156.
157.    bt eax, 31                  ; eax 31-bit copy to CF
158.    jnc _IatName
159.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
160.; Iat ordinal
161.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
162.    movzx edx, ax                   ; edx = ordinal
163.    invoke GetProcAddress, ebx, edx         ; ebx = load dll base
164.    mov [esi - 4], eax
165.    jmp _NextIat
166.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
167.; Iat Name
168.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
169._IatName:
170.    add eax, [esp]                  ; eax = IMAGE_IMPORT_BY_NAME
171.    lea edx, [eax + 2]              ; edx -> api name
172.    invoke GetProcAddress, ebx, edx
173.    mov [esi - 4], eax
174.    jmp _NextIat
175.
176._Next:
177.    add edi, 14h                    ; edi -> next Iat struct
178.    jmp _NextImport
179.
180._II_RetTrue:
181.    pop edx
182.    popad
183.    xor eax, eax
184.    inc eax
185.    ret
186.
187._II_RetFalse:
188.    pop edx
189.    popad
190.    xor eax, eax
191.    ret
192.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
193.; 初始化并修订重定位地址
194.; Arguments:
195.;   [esp]           - return address
196.;   eax             - NT Header
197.;   edx         - alloc mem base
198.; Return Value:
199.;   eax - true or eax - false;
200.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
201.InitFixups:
202.    pushad
203.
204.    mov esi, [eax + 0a0h]               ; esi = reloc rva
205.    test esi, esi
206.    je _IF_RetFalse                 ; No reloc
207.    cld
208.    add esi, edx                    ; esi = 重定位表的地址
209.
210.    push [eax + 0a4h]               ; [esp] = 重定位表长度
211.    add [esp], esi                  ; [esp] = 重定位表结束地址
212.
213.    mov edi, edx                    ; edi = alloc mem base
214.    mov ebp, edx                    ; ebp = alloc mem base
215.    sub ebp, [eax + 34h]                ; ebp等于分配的地址与建议装载地址的差
216.
217._NextFixups:
218.    cmp [esp], esi                  ; 比较是否到了重定位表结束位置
219.    je _IF_RetTrue
220.    lodsd
221.    xchg eax, ebx                   ; ebx = 当前页起始地址RVA
222.    lodsd
223.    xchg eax, ecx                   ; ecx = 当前重定位块的大小
224.    sub ecx, 8
225.    shr ecx, 1                  ; ecx = 重定位项的数量
226.
227._NextOffet:
228.    xor eax, eax
229.    lodsw                       ; eax = 读取重定位项
230.    bt eax, 13                  ; 将eax的第13位复制到CF
231.    jnc _NextLoop
232.
233.    and ax, 0fffh                   ; 保留低12位
234.    add eax, ebx
235.    add dword ptr [edi + eax], ebp          ; 修正,加上差值
236.
237._NextLoop:
238.    loop _NextOffet
239.    jmp _NextFixups
240.
241._IF_RetTrue:
242.    pop edx
243.    popad
244.    xor eax, eax
245.    inc eax
246.    ret
247.
248._IF_RetFalse:
249.    popad
250.    xor eax, eax
251.    ret
252.
253.    end Entry  

时间: 2024-09-30 07:32:33

打造DLL内存加载引擎学习笔记的相关文章

Windows Phone 7 ListBox 列表项渐显加载动画学习笔记

在wp7程序中,当程序功能越来越复杂时,性能问题是我们不得不考虑的一个问题.在聊天列表中,如果聊天项过多,而且项目UI组件足够复杂时, 我们不得不想尽办法让UI尽快加载.所以有一种可行的方案,就是像QQ聊天列表一样,从上至下,列表项逐一加载(加载完第一项,再加载第二项,再加载第三项,给用户尽快的UI响应,也不至于等待到显示所有的列表项. 在我们的例子中,我还给每个列表项显示的过程中加入了渐显动画,这样当列表项足够复杂时,也能表现出比较好的展示效果. 实现的基本原理: 实现的原理也不难,主要的思路

Android知识体系梳理笔记三:动态代理模式---插件加载机制学习笔记

静态代理模式 静态代理模式就是我们常说的代理设计模式,我们采用一个代理类调用原有的方法,且对产生的结果进行控制:举个例子:我们现在在玩一款网络游戏,需要打怪升级:太累就找个代理吧,一觉醒来就会发现我们已经当上CEO,迎娶白富美,天下第一了! 本来我们只能打怪,打怪-,但经过代理类增强,我们不仅可以打怪,还可以升级拿装备.就这样子了! 上代码: * 同一功能接口 public interface PlayNetGame { String beatMonster(); } 1 2 3 4 1 2 3

内存加载DLL

1.前言 目前很多敏感和重要的DLL(Dynamic-link library) 都没有提供静态版本供编译器进行静态连接(.lib文件),即使提供了静态版本也因为兼容性问题导致无法使用,而只提供DLL版本,并且很多专业软件的授权部分的API,都是单独提供一个DLL来完成,而主模块通过调用DLL中的接口来完成授权功能.虽然这些软件一般都采用了加壳和反调试等保护,但是一旦这些功能失去作用,比如脱壳,反反调试,HOOK API或者干脆写一个仿真的授权DLL(模拟授权DLL的所有导出函数接口),然后仿真

cocos2d-js引擎学习笔记

Scale9Sprite 在用Scale9Sprite.create的时候出现Uncaught TypeError: Cannot call method 'create' of undefined这个错误, 后来发现在默认情况下,project.json里的modules只自带cocos2d模块,通过检查frameworks/cocos2d-html5/moduleConfig.json,可以看到cocos2d模块里并没有CCScale9Sprite.js这个类. 它在GUI里,所以可以在mo

固定dll的加载基址的方法

调试dll的时候会有一件事情比较烦人,就是dll加载的地址不会很固定(默认设置下编译的dll基址总是0x10000000,多个同基址的dll加载时,后面的肯定会被重定位),这给前后多次调试时对比分析结果造成了一些麻烦,要解决这个问题,有两种办法.方法一:直接修改dll文件PE头中的ImageBase为一个不大可能被占用的地址.但是这个方法有一个小小的局限,就是有些文件是存在校验的,改了文件之后会出一些问题,比如拒绝加载之类的. 这种情况就要用第二种方法了. 方法二:动态修改dll的加载基址 当然

AMD加载器实现笔记(二)

AMD加载器实现笔记(一)中,我们实现了一个简易的模块加载器.但到目前为止这个加载器还并不能称为AMD加载器,原因很简单,我们还不支持AMD规范中的config配置.这篇文章中我们来添加对config的中baseUrl和packages的支持.API设计如下: 1 require.config({ 2 baseUrl: "./", 3 packages: [{ 4 name: "more", 5 location: "./more" 6 }, {

DLL动态加载时调用类成员函数小结

//dll 动态加载  调用 类 函数小结: 静态加载时,调用类成员函数,很简单.此次研究了下动态加载. 首先困难点:The first problem is that C++ member function names are decorated names (Specifying extern "C" does not help).The second problem is that C++ language specifications do not allow pointer

IE报错:模块"scrrun.dll"已加载,但对DllRegisterServer的调用失败,错误代码为0x80004005

在我的win10系统上打开某内部网页登录的时候弹出'模块"scrrun.dll"已加载,但对DllRegisterServer的调用失败,错误代码为0x80004005'报错信息,搞了好久都没有 搞好,最后百度找到注册文件“clock.zip”运行其中的批处理文件后成功登陆. 注册文件链接:http://files.cnblogs.com/files/xxlu/clock.zip 注意:在注册的时候要将批处理文件run.bat中clock.ocx组件的地址改为本地绝对地址,博主提供的r

CS0009:未能打开元数据文件System.ComponentModel.DataAnnotations.dll 试图加载格式不正确的程序。

问题描述: CS0009: 未能打开元数据文件“c:\Windows\Microsoft.NET\assembly\GAC_MSIL \System.ComponentModel.DataAnnotations\v4.0_4.0.0.0__31bf3856ad364e35 \System.ComponentModel.DataAnnotations.dll”--“试图加载格式不正确的程序. 网上搜索出来的资源比较少,修复VS也没有用,特地写这小文章. 试了网上方法: 把"C:\Windows\M