首页
社区
课程
招聘
关于LCCrypto中的重定位
发表于: 2010-7-28 10:35 3933

关于LCCrypto中的重定位

2010-7-28 10:35
3933
下载:http://www.luocong.com/myworks/zipped/LCCrypto.zip

其中,有一段代码貌似是对PE中的Call、Push、Jmp等进行了重定向。例如原始节中,VirtualAddress是0x1000, 节中的代码就是Call 1001h。但是在写入别的PE的节时,新节的VirtualAddress可能是0x3000。就必须将要拷贝的节中的Call 1001h 改成 Call 3001h。这是什么原理?小弟不懂OpCode。请各位大牛指教。

重定向代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@@copy:
    mov eax, [esi]
    and eax, NOT 00000FFFh
    cmp eax, attach_data_start
    .if zero?
        mov eax, [esi]
        sub eax, attach_start
        add eax, [img_nt_hdrs.OptionalHeader.ImageBase]
        add eax, [img_sect_hdr.VirtualAddress]
        mov [esi], eax
    .endif
    inc esi
    loopd @@copy
    mov eax, [img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
    add eax, [img_nt_hdrs.OptionalHeader.ImageBase]
    mov dword ptr [bNew + @@oep], eax


写入新节代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
;*********************************************************
;写入加密节的模块
;*********************************************************
Protect proc    uses ebx ecx edx esi edi
    LOCAL bOK: BOOL
 
    mov bOK, TRUE
 
    ;挂接 SEH 处理链,不用多说了吧,呵呵:
    assume  fs:nothing
    push    offset ErrorHandler
    push    fs:[0]
    mov     [SEH], esp
    mov     [SEH+4], ebp
    mov     [SEH+8], ebx
    mov     [SEH+12], esi
    mov     [SEH+16], edi
    mov     [SEH+20], offset @@safe
    mov     fs:[0], esp
 
    ;获得文件名和密码:
    invoke  GetDlgItemText, [mbp.hwndOwner], IDC_EDIT_FILENAME, addr szFileName, sizeof szFileName
    invoke  GetDlgItemText, [mbp.hwndOwner], IDC_EDIT_PASSWORD, addr szPassword, sizeof szPassword
    invoke  GetDlgItemText, [mbp.hwndOwner], IDC_EDIT_PASSWORD_2, addr szPassword_2, sizeof szPassword_2
 
    ;打开文件:
    invoke CreateFile, addr szFileName, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
 
    ;如果打开文件失败,进行处理:
    .if eax == INVALID_HANDLE_VALUE
        invoke MessageBox, mbp.hwndOwner, CTEXT("打开文件失败!"), addr szCaption, MB_OK or MB_ICONHAND
        invoke GetDlgItem, mbp.hwndOwner, IDC_EDIT_FILENAME
        invoke SetFocus, eax
        invoke SendMessage, eax, EM_SETSEL, 0, -1
        mov bOK, FALSE
        jmp _Err_CreateFile_Exit
    .endif
 
    ;复制文件句柄:
    mov hFile, eax
 
    ;取得密码的长度:
    invoke lstrlen, addr szPassword
 
    ;如果密码长度为0,进行处理:
    .if eax == 0
        invoke MessageBox, mbp.hwndOwner, CTEXT("请先输入密码!"), addr szCaption, MB_OK or MB_ICONHAND
        invoke GetDlgItem, mbp.hwndOwner, IDC_EDIT_PASSWORD
        invoke SetFocus, eax
        mov bOK, FALSE
        jmp @@safe
    .endif
 
    ;比较两次输入的密码是否相同,如不同,进行处理:
    invoke lstrcmp, addr szPassword, addr szPassword_2
    .if eax != 0
        invoke MessageBox, mbp.hwndOwner, CTEXT("两次输入的密码不符,请检查您的输入!"), addr szCaption, MB_OK or MB_ICONHAND
        mov bOK, FALSE
        jmp @@safe
    .endif
 
    ;判断“保留备份文件”是否被选中,如果选中了,则备份原文件,备份文件名是在原文件名的最后加“.bak”:
    invoke IsDlgButtonChecked, mbp.hwndOwner, IDC_CHECKBOX_KEEPBACKUP
    .if eax == BST_CHECKED
        invoke lstrcpy, addr szFileNameBak, addr szFileName
        invoke lstrcat, addr szFileNameBak, CTEXT(".bak")
        invoke CopyFile, addr szFileName, addr szFileNameBak, FALSE
    .endif
 
    ;读入 PE 文件的 IMAGE_DOS_HEADER :
    invoke  ReadFile, hFile, addr img_dos_hdr, sizeof img_dos_hdr, esp, 0
 
    ;判断是否为一个有效的 PE 文件,呵呵,这个不用多解释了吧?
    cmp [img_dos_hdr.e_magic], "ZM"
    .if !zero?
        invoke MessageBox, [mbp.hwndOwner], CTEXT("这不是一个有效的 PE 文件!"), addr szCaption, MB_OK or MB_ICONHAND
        mov bOK, FALSE
        jmp @@safe
    .endif
 
    ;把文件指针指向 IMAGE_NT_HEADERS,并读入该部分内容:
    invoke  SetFilePointer, hFile, img_dos_hdr.e_lfanew, 0, FILE_BEGIN
    invoke  ReadFile, hFile, addr img_nt_hdrs, sizeof img_nt_hdrs, esp, 0
 
    ;同样,判断是否为一个有效的 PE 文件,呵呵,这个不用多解释了吧?
    cmp [img_nt_hdrs.Signature], "EP"
    .if !zero?
        invoke MessageBox, [mbp.hwndOwner], CTEXT("这不是一个有效的 PE 文件!"), addr szCaption, MB_OK or MB_ICONHAND
        mov bOK, FALSE
        jmp @@safe
    .endif
 
    ;储存一些数据,后面会用到:
    xor     eax, eax
    xor     edx, edx
    movzx   ecx, [img_nt_hdrs.FileHeader.NumberOfSections]
 
@@s000:
    push    ecx
    push    eax
    push    edx
 
    ;读入 IMAGE_SECTION_HEADER 内容:
    invoke  ReadFile, hFile, addr img_sect_hdr, sizeof img_sect_hdr, esp, 0
 
    ;判断是否已被加密过:
    invoke lstrcmp, CTEXT(".LC"), addr [img_sect_hdr.Name1]
    .if eax == 0
        invoke MessageBox, [mbp.hwndOwner], CTEXT("您忘记了?文件已被加密过啦……"), addr szCaption, MB_OK or MB_ICONHAND
        mov bOK, FALSE
        jmp @@safe
    .endif
 
    ;查找可以插入新节的位置:
    pop edx
    mov eax, img_sect_hdr.PointerToRawData
    add eax, img_sect_hdr.SizeOfRawData
    cmp eax, edx
    jbe @@s001
    mov edx, eax
@@s001:
    pop eax
    mov ecx, [img_sect_hdr.VirtualAddress]
    add ecx, [img_sect_hdr.Misc.VirtualSize]
    cmp eax, ecx
    jae @@s002
    mov eax, ecx
@@s002:
    pop ecx
    loopd   @@s000
 
    ;新节的名称为“.LC”,呵呵:
    mov dword ptr [img_sect_hdr.Name1+00h], "CL."
    ;填充剩下的字段:
    mov [img_sect_hdr.Misc.VirtualSize], attach_size
    mov [img_sect_hdr.VirtualAddress], eax
    mov [img_sect_hdr.SizeOfRawData], attach_size
    mov [img_sect_hdr.PointerToRawData], edx
    mov [img_sect_hdr.PointerToRelocations], ecx
    mov [img_sect_hdr.PointerToLinenumbers], ecx
    mov dword ptr [img_sect_hdr.NumberOfRelocations], ecx
 
    ;计算新节的加载RVA:
    mov edx, 00000FFFh
    test [img_sect_hdr.VirtualAddress], edx
    .if !zero?
        and edx, [img_sect_hdr.VirtualAddress]
        sub edx, 1000h
        neg edx
        add [img_sect_hdr.VirtualAddress], edx
    .endif
 
    ;计算新节的 PointerToRawData 的偏移值:
    ;(经过试验,200h是在 Win2k/XP 中能被正确加载的比较保险的值)
    xor edx, edx
    mov eax, [img_sect_hdr.PointerToRawData]
    mov ecx, 200h
    div ecx
    test edx, edx
    .if !zero?
        sub edx, 200h
        neg edx
        add [img_sect_hdr.PointerToRawData], edx
    .endif
 
    ;设置新节的属性:
    ;code/data/execute/read/write/inited data/un-inited data:(一股脑都加上了,呵呵,这样可以避免出错)
    mov [img_sect_hdr.Characteristics], 0E00000E0h
 
    ;把新节信息(IMAGE_SECTION_HEADER)写入文件:
    invoke  WriteFile, [hFile], addr img_sect_hdr, sizeof img_sect_hdr, esp, 0
 
    ;定位到新节的起始偏移地址:
    invoke  SetFilePointer, [hFile], [img_sect_hdr.PointerToRawData], 0, FILE_BEGIN
 
    ;把一些有用的信息压栈,后面会用到:
    push esi
    push edi
    mov esi, attach_start
    mov edi, offset bNew
    mov ecx, attach_size shr 2
    rep movsd
    mov ecx, attach_size and 3
    rep movsb
    mov esi, offset bNew
    mov ecx, attach_size
 
    ;改写原程序的代码段的第一条指令的入口地址:
@@copy:
    mov eax, [esi]
    and eax, NOT 00000FFFh
    cmp eax, attach_data_start
    .if zero?
        mov eax, [esi]
        sub eax, attach_start
        add eax, [img_nt_hdrs.OptionalHeader.ImageBase]
        add eax, [img_sect_hdr.VirtualAddress]
        mov [esi], eax
    .endif
    inc esi
    loopd @@copy
    mov eax, [img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
    add eax, [img_nt_hdrs.OptionalHeader.ImageBase]
    mov dword ptr [bNew + @@oep], eax
 
    ;初始化crc32table:
    invoke init_crc32table_m
 
    ;下面赋值给寄存器ebx,以便进行crc32转换:
    ;EBX是待转换的字符串的首地址:
    lea ebx, szPassword
 
    ;进行crc32转换:
    invoke arraycrc32_m
 
    ;转换后的密码存放在 [esi] 中:
    mov dword ptr [esi], eax
 
    ;把转换后的密码加入到新节里面:
    mov edi, offset bNew + (offset _szRealPassword - attach_start)
    mov ecx, 4
    rep movsd
    pop edi
    pop esi
 
    ;真正把整个新节的内容写入原程序:
    invoke  WriteFile, [hFile], addr bNew, attach_size, esp, 0
    invoke  SetFilePointer, [hFile], [img_dos_hdr.e_lfanew], 0, FILE_BEGIN
    mov eax, [img_sect_hdr.VirtualAddress]
    add eax, attach_code_start - attach_start
    inc [img_nt_hdrs.FileHeader.NumberOfSections]
    mov [img_nt_hdrs.OptionalHeader.AddressOfEntryPoint], eax
    add [img_nt_hdrs.OptionalHeader.SizeOfImage], attach_size
    ;下面两句非常重要,否则加密后的程序在 Win2k 以上的系统中运行会有错误:(感谢vBin兄的指点!)
    push 0
    pop [img_nt_hdrs.OptionalHeader.DataDirectory(11).VirtualAddress]
    invoke  WriteFile, [hFile], addr img_nt_hdrs, sizeof img_nt_hdrs, esp, 0
 
    ;安全的文件关闭点:
@@safe:
    invoke CloseHandle, [hFile]
 
    ;如果一开始的打开文件出错,就会来到这里:
_Err_CreateFile_Exit:
    ;如果操作全部完成并没有错误发生,就显示成功提示:
    .if bOK == TRUE
        invoke  MessageBox, [mbp.hwndOwner], CTEXT("加密成功完成!请记住您的密码!"), addr szCaption, MB_OK or MB_ICONINFORMATION
    .endif
 
    ;取消 SEH 链表:
    pop fs:[0]
    add esp, 4
 
    ;结束啦!哈
    ret
Protect endp

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费
支持
分享
最新回复 (1)
雪    币: 43
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
其实那个代码没什么要点,就是逐位地向后搜索,比较地址的高位是否和基质相同。如果相同,就认为这是地址,加减运算后写入。
这也许就是所谓的“坟贴”吧……
2010-7-28 13:21
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册