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

关于LCCrypto中的重定位

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

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

重定向代码:
@@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


写入新节代码:
;*********************************************************
;写入加密节的模块
;*********************************************************
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

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

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