什么是WINDOWS的资源这里就不提了。写过WIN程序的人应该都晓得了。如果没写过,那么。。。建议去写哈。
关于加密资源节,也是加壳过程中的一个可选项而已。加和不加都不太对破解造成影响。但是如果
你的程序中,有一些重要数据在资源节里面而你又不想让其他人通过资源浏览器参看到,那么这个
时候加密资源节就有必要了。在这里节,我们首先了解一下资源节在PE文件中的结构。其次,编写
一个简单的资源浏览器用于熟悉资源节的结构。最后,完成一个加密与解密资源节的小程序。
资源节可以说在PE结构中最复杂的一个结构了。整体是一个2叉树结构。
总共有3层。第一层是类型,第二层是名称,第三层是语言,在语言后面就是一个指向资源数据的位置的结构了。
下面将资源节的结构如图:
资源节结构图:
附件中查看 呵呵。。。
资源节处于数据目录的第三项可以通过微软预定义的宏IMAGE_DIRECTORY_ENTRY_RESOURCE来定位资源
节的数据目录。通过VirtualAddress转换文件偏移 + 文件映射地址就得到了资源节所在文件的位置
节内容的起始是一个被称为资源目录表的结构,如下:
IMAGE_RESOURCE_DIRECTORY STRUCT
Characteristics dd ?
TimeDateStamp dd ?
MajorVersion dw ?
MinorVersion dw ?
NumberOfNamedEntries dw ?
NumberOfIdEntries dw ?
IMAGE_RESOURCE_DIRECTORY ENDS
Characteristics:资源标志,保留,设置为0
TimeDataStamp:时间戳,由资源编译器设定
MajorVersion:主版本号,由用户设定
MinorVersion:次版本号,由用户设定
以下这两项是我们说要关心的
NumberOfNamedEntries:通过字符串来定义的资源
NumberOfIdEntries:用过序号来定义的资源
这两项的和为引入资源的总数,在这个结构后面是一组由IMAGE_RESOURCE_DIRECTORY_ENTRY组成的数组
具体个数为NumberOfNamedEntries + NumberOfIdEntries
以下为结构的说明:
IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT
union
rName RECORD NameIsString:1,NameOffset:31
Name1 dd ?
Id dw ?
ends
union
OffsetToData dd ?
rDirectory RECORD DataIsDirectory:1,OffsetToDirectory:31
ends
IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS
这个结构在不同的位置是不同的意义。
在第一层的为类型,Name1代表的是一个类型,在资源类型方面有16个基本类型
"RT_CURSOR"
"RT_BITMAP"
"RT_ICON"
"RT_MENU"
"RT_DIALOG"
"RT_STRING"
"RT_FONTDIR"
"RT_FONT"
"RT_ACCELERATOR"
"RT_RCDATA"
"DIFFERENCE"
"RT_GROUP_CURSOR"
"RT_GROUP_ICON"
"RT_VERSION"
也有更多的类型,这方面的资料很少。我也没有能收集全,RT_RCDATA类型表示为自定义的。
这里为标准的类型值。
在第二层时:如果Name的2进制最高位时候1,那么它表示一个以名字引出的资源,此时Name的低2位表示一个从资源节开头到它的偏移
使用Name的低2位值 + 资源节开头的地址 指向一个IMAGE_RESOURCE_DIRECTORY_STRING结构。资源的名字使用UNICODE编码。
IMAGE_RESOURCE_DIRECTORY_STRING STRUCT
Length1 dw ?
NameString db ?
IMAGE_RESOURCE_DIRECTORY_STRING ENDS
Length1表示有几个字母
NameString为以双0结尾的UNICODE字符串。
在第三层时,Name表示资源所用语言的代码。
OffsetToData:这个字段在不同层都表示一个到资源节开头的偏移。
不同的是,如果OffsetToData的2进制最高位是1,表示还有下面的其他层(语言层或者名字层,类型层总是存在)。
如果是0,则表示一个到IMAGE_RESOURCE_DATA_ENTRY的偏移
IMAGE_RESOURCE_DATA_ENTRY STRUCT
OffsetToData dd ?
Size1 dd ?
CodePage dd ?
Reserved dd ?
IMAGE_RESOURCE_DATA_ENTRY ENDS
OffsetTOData表示到资源数据的偏移,这个偏移是到加载地址(ImageBase)的偏移。
Size1为数据的长度
CodePage:一般为0
Reserved:一般为0
接下来看段代码可能会更清晰一些。
ResViewEntry proc uses ebx ecx edx edi esi pEntry : LPVOID, dwLevel : DWORD
LOCAL szOutFileName[MAX_PATH] : BYTE
;; level = 0,1,2
mov esi, pEntry
assume esi : ptr IMAGE_RESOURCE_DIRECTORY
[COLOR=Red];; 计算有几个资源在当前目录下[/COLOR]
mov cx, word ptr [esi].NumberOfNamedEntries
add cx, word ptr [esi].NumberOfIdEntries
movzx ecx, cx
[COLOR=Red];; 这里存在着ecx个IMAGE_RESOURCE_DIRECTORY_ENTR[/COLOR]Y
add esi, sizeof IMAGE_RESOURCE_DIRECTORY
mov edi, esi
assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
ResDirEntryLoop:
[COLOR=Red] ;; 打印资源层[/COLOR]
invoke JudegeResourceEntryLevel, edi, dwLevel
mov eax, dword ptr [edi].OffsetToData
test eax, FIRSTBIT
jz FoundTheDataEntry
and eax, 0000FFFFh
add eax, g_pResSection
mov edx, dwLevel
inc edx
invoke ResViewEntry, eax, edx
jmp ContinueResDirEntryLoop
FoundTheDataEntry:
[COLOR=Red];; 取出资源文件[/COLOR]
add eax, g_pResSection
assume eax : ptr IMAGE_RESOURCE_DATA_ENTRY
mov edx, dword ptr [eax].Size1
mov eax, dword ptr [eax].OffsetToData
[COLOR=Red];; 转化RVA到偏移[/COLOR]
invoke RVA2Offset, g_pMem, eax
push eax
push ecx
push edx
invoke wsprintf, addr szOutFileName, offset g_szOutOrdFormat, eax
pop edx
pop ecx
pop eax
add eax, g_pMem
invoke OutputToFile, addr szOutFileName, eax, edx
ContinueResDirEntryLoop:
add edi, sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY
dec ecx
test ecx, ecx
jnz ResDirEntryLoop
assume esi : nothing
assume edi : nothing
ret
ResViewEntry endp
JudegeResourceEntryLevel proc uses ebx ecx edx edi esi pResEntry : LPVOID, dwLevel : DWORD
LOCAL szTmpBuf[MAX_PATH] : BYTE
;; init local variable
mov ecx, MAX_PATH
lea edi, szTmpBuf
xor eax, eax
cld
rep stosb
mov edi, pResEntry
assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
mov eax, dwLevel
cmp eax, 0
jnz JudgeLevelOne
[COLOR=Red];; 显示类型[/COLOR]
mov eax, dword ptr [edi].Name1
invoke ShowResourceType, eax
jmp ExitJudgeLevel
JudgeLevelOne:
cmp eax, 1
jnz JudgeLevelTwo
[COLOR=Red];; 显示名称[/COLOR]
mov eax, dword ptr [edi].Name1
[COLOR=Red];; 最高位是0时表示使用ID[/COLOR]
test eax, FIRSTBIT
jz UseID
and eax, 0000FFFFh
add eax, g_pResSection
assume eax : ptr IMAGE_RESOURCE_DIR_STRING_U
lea esi, [eax].NameString
lea edi, szTmpBuf
[COLOR=Red];; 拷贝字符串到局部变量[/COLOR]
mov cx, word ptr [eax].Length1
movzx ecx, cx
cld
rep movsw
invoke crt_printf, offset g_szOutFormat, offset g_szResNameByStr
invoke crt_wprintf, addr szTmpBuf
invoke crt_printf, offset g_szOutFormat, offset g_szEndLine
jmp ExitJudgeLevel
UseID:
invoke crt_printf, offset g_szResNameById, eax
jmp ExitJudgeLevel
JudgeLevelTwo:
[COLOR=Red];; 第三次是语言,这里输出语言定义的常量[/COLOR]
mov eax, dword ptr [edi].Name1
invoke crt_printf, offset g_szResLang, eax
ExitJudgeLevel:
assume eax : nothing
assume edi : nothing
ret
JudegeResourceEntryLevel endp
很简单对吧!。。。 这段在附件中的程序打印资源的类型,名称/ID,语言代码,还有将资源dump到一个目录中。
接下来就改讲解一下加解密资源节了,其实与列出资源节的算法一样。这里使用的加密算法也很简单只是简单的XOR了一哈。
不过要注意的是。有些资源是不可以加密的。例如ICON还有寻找ICON偏移的ICON_GROUP还有版本信息等,还有其他的,总之在PE加载器在代码段之前加载的资源是不可以加密,否则程序不能运行。这里的加密程序不加密ICON ICON_GROUP VERSION这三种类型,如果你遇到加密资源后程序无法运行那可以就是加了不该加的资源了。呵呵,自行修改下代码吧。加密在JudegeResourceType处添加过滤,解密在JudgeDecryptResType处修改,代码很简单一看就明白
下面列出加解密代码
首先是加密的
EncryptResSec proc uses ebx ecx edx edi esi pEntry : LPVOID, dwLevel : DWORD
;; level = 0,1,2
mov esi, pEntry
assume esi : ptr IMAGE_RESOURCE_DIRECTORY
[COLOR=Red];; 计算有几个资源在当前目录下[/COLOR]
mov cx, word ptr [esi].NumberOfNamedEntries
add cx, word ptr [esi].NumberOfIdEntries
movzx ecx, cx
[COLOR=Red];; 这里存在着ecx个IMAGE_RESOURCE_DIRECTORY_ENTRY[/COLOR]
add esi, sizeof IMAGE_RESOURCE_DIRECTORY
mov edi, esi
assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
ResDirEntryLoop:
[COLOR=Red] ;; 加密资源层
;; 清除加密标志,如果是0级别则清除[/COLOR]
cmp dwLevel, 0
jnz SkipClearEncryptFlag
push 0
pop g_dwEncrypt
SkipClearEncryptFlag:
invoke JudegeResourceType, edi, dwLevel
mov eax, dword ptr [edi].OffsetToData
test eax, FIRSTBIT
jz FoundTheDataEntry
and eax, 0000FFFFh
add eax, g_pResSection
mov edx, dwLevel
inc edx
invoke EncryptResSec, eax, edx
jmp ContinueResDirEntryLoop
FoundTheDataEntry:
[COLOR=Red];; 加密资源文件[/COLOR]
mov ebx, g_dwEncrypt
test ebx, ebx
jz ContinueResDirEntryLoop
add eax, g_pResSection
assume eax : ptr IMAGE_RESOURCE_DATA_ENTRY
mov edx, dword ptr [eax].Size1
mov eax, dword ptr [eax].OffsetToData
[COLOR=Red];; 转化RVA到偏移[/COLOR]
invoke RVA2Offset, g_pMem, eax
add eax, g_pMem
[COLOR=Red];; 加密资源[/COLOR]
EncryptResourceData:
push edi
push esi
push ecx
mov edi, eax
mov esi, edi
mov ecx, edx
cld
EnResourceLoop:
lodsb
xor al, CRYPT_KEY
stosb
loop EnResourceLoop
pop ecx
pop esi
pop edi
ContinueResDirEntryLoop:
add edi, sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY
dec ecx
test ecx, ecx
jnz ResDirEntryLoop
assume esi : nothing
assume edi : nothing
ret
EncryptResSec endp
JudegeResourceType proc uses eax edi pResEntry : LPVOID, dwLevel : DWORD
[COLOR=Red] ;; 不加密ICON,ICON_GROUP,还有版本信息
;; 在PE加载器加载时要读取这些资源
;; 否则程序会崩溃[/COLOR]
mov edi, pResEntry
assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
mov eax, dwLevel
[COLOR=Red];; 不是类型层,直接退出 [/COLOR]
cmp eax, 0
jnz ExitJudgeLevel
;; 显示类型
mov eax, dword ptr [edi].Name1
cmp eax, RT_ICON
jnz CmpICON_GROUP
jmp ExitJudgeLevel
CmpICON_GROUP:
cmp eax, RT_GROUP_ICON
jnz CmpVERSION
jmp ExitJudgeLevel
CmpVERSION:
cmp eax, RT_VERSION
jnz EncryptData
ExitJudgeLevel:
assume eax : nothing
assume edi : nothing
ret
EncryptData:
push 1
pop g_dwEncrypt
jmp ExitJudgeLevel
JudegeResourceType endp
解密代码如下:
CryptResource proc pFileName : LPSTR
LOCAL hFile : HANDLE
LOCAL hMap : HANDLE
LOCAL pMem : LPVOID
LOCAL dwAppendSize : DWORD
LOCAL dwNTHeaderAddr : DWORD
LOCAL dwImageBase : DWORD
LOCAL dwOrigEntryAddr : DWORD
LOCAL dwResSecVA : DWORD
;; init data
xor eax, eax
mov g_bError, al
mov eax, offset EndDecryptResource - offset DecryptResource
mov g_dwDecryptResourceSize, eax
;; get the append size
invoke CountAppendSize, pFileName
.IF eax == 0
jmp GetFileSizeFailed
.ENDIF
mov dwAppendSize, eax
;; open file
invoke CreateFile, pFileName,\
GENERIC_WRITE + GENERIC_READ,\
FILE_SHARE_WRITE + FILE_SHARE_READ,\
NULL,\
OPEN_EXISTING,\
FILE_ATTRIBUTE_NORMAL,\
0
.IF eax == INVALID_HANDLE_VALUE
jmp OpenFileFailed
.ENDIF
mov hFile, eax
; ;; get file size
; invoke GetFileSize, eax, NULL
; .IF eax == 0
; jmp GetFileSizeFailed
; .ENDIF
mov eax, dwAppendSize
xchg eax, ecx
;; create memory map
xor ebx, ebx
invoke CreateFileMapping, hFile, ebx, PAGE_READWRITE, ebx, ecx, ebx
.IF eax == 0
invoke CloseHandle, hFile
jmp CreateMapFailed
.ENDIF
mov hMap, eax
;; map file to memory
xor ebx, ebx
invoke MapViewOfFile, hMap,
FILE_MAP_WRITE + FILE_MAP_READ + FILE_MAP_COPY,
ebx, ebx, ebx
.IF eax == 0
invoke CloseHandle, hMap
invoke CloseHandle, hFile
jmp MapFileFailed
.ENDIF
mov pMem, eax
mov g_pMem, eax
;; check it's PE file or not ?
xchg eax, esi
assume esi : ptr IMAGE_DOS_HEADER
.IF [esi].e_magic != 'ZM'
invoke UnmapViewOfFile, pMem
invoke CloseHandle, hMap
invoke CloseHandle, hFile
jmp InvalidPE
.ENDIF
add esi, [esi].e_lfanew
assume esi : ptr IMAGE_NT_HEADERS
.IF word ptr [esi].Signature != 'EP'
invoke UnmapViewOfFile, pMem
invoke CloseHandle, hMap
invoke CloseHandle, hFile
jmp InvalidPE
.ENDIF
;; store basic PE orig information
mov dwNTHeaderAddr, esi
assume esi : ptr IMAGE_NT_HEADERS
mov eax, dword ptr [esi].OptionalHeader.ImageBase
mov dwImageBase, eax
mov eax, dword ptr [esi].OptionalHeader.AddressOfEntryPoint
add eax, dwImageBase
mov dwOrigEntryAddr, eax
[COLOR=Red];; 判断是否存在资源节[/COLOR]
mov eax, dword ptr [esi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE * sizeof IMAGE_DATA_DIRECTORY].VirtualAddress
.IF eax == 0
jmp NoResourceSec
.ENDIF
mov ebx, eax
add ebx, dwImageBase
mov dwResSecVA, ebx [COLOR=Red]; ebx 为资源节在内存中的地址[/COLOR]
[COLOR=Red];; 转变为FVA[/COLOR]
invoke RVA2Offset, pMem, eax
add eax, pMem
mov g_pResSection, eax
[COLOR=Red] ;; 加密资源节[/COLOR]
invoke EncryptResSec, eax, 0
[COLOR=Red];; 升级数据[/COLOR]
lea eax, DecryptRes_dwOrigEntryAddress
push dwOrigEntryAddr
pop dword ptr [eax]
lea eax, DecryptRes_ResVA
push dwResSecVA
pop dword ptr [eax]
lea eax, DecryptRes_ImageBase
push dwImageBase
pop dword ptr [eax]
[COLOR=Red];; 添加解密节[/COLOR]
invoke AddSection, pMem, NULL, g_dwDecryptResourceSize
mov esi, eax
assume esi : ptr IMAGE_SECTION_HEADER
[COLOR=Red];; 更新入口点与SizeOfImage[/COLOR]
mov edi, dwNTHeaderAddr
assume edi : ptr IMAGE_NT_HEADERS
[COLOR=Red] ;; 更改资源节属性[/COLOR]
mov eax, dword ptr [edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE * sizeof IMAGE_DATA_DIRECTORY].VirtualAddress
invoke FindSectionTable, pMem, eax
assume eax : ptr IMAGE_SECTION_HEADER
push 0E00000E0h [COLOR=Red]; 可读可写可执行[/COLOR]
pop dword ptr [eax].Characteristics
push dword ptr [esi].VirtualAddress
pop dword ptr [edi].OptionalHeader.AddressOfEntryPoint
mov eax, dword ptr [esi].VirtualAddress
add eax, dword ptr [esi].Misc.VirtualSize
mov ebx, dword ptr [edi].OptionalHeader.SectionAlignment
invoke PEAlign, eax, ebx
push eax
pop dword ptr [edi].OptionalHeader.SizeOfImage
[COLOR=Red];; 将解密节写入[/COLOR]
mov edi, dword ptr [esi].PointerToRawData
add edi, pMem
lea esi, DecryptResource
mov ecx, g_dwDecryptResourceSize
cld
rep movsb
LogicShellExit:
;; close handle & write it
invoke UnmapViewOfFile, pMem
invoke CloseHandle, hMap
invoke CloseHandle, hFile
.IF g_bError == 0
;; show success message
invoke crt_printf, offset g_szOutFormat, offset g_szDone
.ENDIF
assume eax : nothing
assume esi : nothing
assume edi : nothing
ret
;; ----- Show error message -----
OpenFileFailed:
lea eax, g_szOpenFileFailed
jmp ShowErr
GetFileSizeFailed:
lea eax, g_szGetFileSizeFailed
jmp ShowErr
CreateMapFailed:
lea eax, g_szCreateMapFailed
jmp ShowErr
MapFileFailed:
lea eax, g_szMapFileFailed
jmp ShowErr
InvalidPE:
lea eax, g_szInvalidPE
jmp ShowErr
NoResourceSec:
lea eax, g_szNoResTbl
jmp ShowErr
ShowErr:
invoke crt_printf, offset g_szOutFormat, eax
mov al, 1
mov g_bError, al
jmp LogicShellExit
[COLOR=Red];; ----- 解密资源节 -----[/COLOR]
DecryptResource:
DecryptResourceStackSize equ 10h
DecryptResource_Eip equ -04h
DecruptResource_dwFlags equ -08h
push ebp
mov ebp, esp
sub esp, DecryptResourceStackSize
[COLOR=Red];; 清0堆栈[/COLOR]
mov edi, esp
mov ecx, DecryptResourceStackSize
cld
xor eax, eax
rep stosb
call GetEip
GetEip:
pop eax
sub eax, offset GetEip - offset DecryptResource
mov dword ptr [ebp+DecryptResource_Eip], eax
add eax, offset DecryptRes_ResVA - offset DecryptResource
push 0 ; Level
push dword ptr [eax] ; ResVA
push dword ptr [eax] ; pEntry
call RecDecryptRes
[COLOR=Red];; 读取原入口点[/COLOR]
mov eax, offset DecryptRes_dwOrigEntryAddress - offset DecryptResource
add eax, dword ptr [ebp+DecryptResource_Eip]
mov eax, dword ptr [eax]
mov esp, ebp
pop ebp
jmp eax
[COLOR=Red];; ----- 解密资源节数据 -----[/COLOR]
DecryptRes_dwOrigEntryAddress dd 0
DecryptRes_ResVA dd 0
DecryptRes_bDecrypt dd 0
DecryptRes_ImageBase dd 0
[COLOR=Red] ;; ----- 递归解密资源节的函数 -----[/COLOR]
RecDecryptRes:
RecDecryptResArg_Entry equ 08h
RecDecryptResArg_ResVA equ 0ch
ResDecryptRes_dwLevel equ 10h
ResDecryptResStackSize equ 04h
ResDecryptRes_Eip equ -04h
push ebp
mov ebp, esp
sub esp, ResDecryptResStackSize
push ebx
push ecx
push edx
push edi
push esi
[COLOR=Red];; 获取eip[/COLOR]
call GetRecDecryptResEip
GetRecDecryptResEip:
pop ebx
sub ebx, offset GetRecDecryptResEip - offset RecDecryptRes
mov dword ptr [ebp+ResDecryptRes_Eip], ebx
mov esi, dword ptr [ebp+RecDecryptResArg_Entry]
assume esi : ptr IMAGE_RESOURCE_DIRECTORY
[COLOR=Red];; 计算有几个资源在当前目录下[/COLOR]
mov cx, word ptr [esi].NumberOfNamedEntries
add cx, word ptr [esi].NumberOfIdEntries
movzx ecx, cx
[COLOR=Red];; 这里存在着ecx个IMAGE_RESOURCE_DIRECTORY_ENTRY[/COLOR]
add esi, sizeof IMAGE_RESOURCE_DIRECTORY
mov edi, esi
assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
ResDeDirEntryLoop:
[COLOR=Red] ;; 解密资源层
;; 是0级别则清除[/COLOR]
cmp dword ptr [ebp+ResDecryptRes_dwLevel], 0
jnz SkipClearDecryptFlag
push 0
mov eax, dword ptr [ebp+ResDecryptRes_Eip]
sub eax, offset RecDecryptRes - offset DecryptRes_bDecrypt
pop dword ptr [eax]
SkipClearDecryptFlag:
push dword ptr [ebp+ResDecryptRes_dwLevel]
push edi
call JudgeDecryptResType
mov eax, dword ptr [edi].OffsetToData
test eax, FIRSTBIT
jz FoundTheDeDataEntry
and eax, 0000FFFFh
add eax, dword ptr [ebp+RecDecryptResArg_ResVA]
mov edx, dword ptr [ebp+ResDecryptRes_dwLevel]
inc edx
push edx
push dword ptr [ebp+RecDecryptResArg_ResVA]
push eax
call RecDecryptRes
jmp ContinueResDeDirEntryLoop
FoundTheDeDataEntry:
[COLOR=Red];; 取出资源文件[/COLOR]
mov ebx, dword ptr [ebp+ResDecryptRes_Eip]
sub ebx, offset RecDecryptRes - offset DecryptRes_bDecrypt
mov ebx, dword ptr [ebx]
test ebx, ebx
jz ContinueResDeDirEntryLoop
[COLOR=Red];; ebx 不为0则解密[/COLOR]
add eax, dword ptr [ebp+RecDecryptResArg_ResVA]
assume eax : ptr IMAGE_RESOURCE_DATA_ENTRY
mov edx, dword ptr [eax].Size1
mov eax, dword ptr [eax].OffsetToData
mov ebx, dword ptr [ebp+ResDecryptRes_Eip]
sub ebx, offset RecDecryptRes - offset DecryptRes_ImageBase
mov ebx, dword ptr [ebx]
add eax, ebx
[COLOR=Red];; 解密资源[/COLOR]
push edi
push esi
push ecx
mov edi, eax
mov esi, edi
mov ecx, edx
cld
DeResourceLoop:
lodsb
xor al, CRYPT_KEY
stosb
loop DeResourceLoop
mov esi, dword ptr [ebp+ResDecryptRes_Eip]
sub esi, offset RecDecryptRes - offset DecryptRes_bDecrypt
push 0
pop dword ptr [esi]
pop ecx
pop esi
pop edi
ContinueResDeDirEntryLoop:
add edi, sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY
dec ecx
test ecx, ecx
jnz ResDeDirEntryLoop
assume esi : nothing
assume edi : nothing
pop esi
pop edi
pop edx
pop ecx
pop ebx
mov esp, ebp
pop ebp
retn 0ch
[COLOR=Red];; ----- 判断资源类型 -----[/COLOR]
JudgeDecryptResType:
JudgeDecryptResArg_Entry equ 08h
JudgeDecryptResArg_dwLevel equ 0ch
push ebp
mov ebp, esp
push eax
push edi
push ebx
push esi
[COLOR=Red];; 获取EIP[/COLOR]
call GetJudgeDecryptEip
GetJudgeDecryptEip:
pop esi
sub esi, offset GetJudgeDecryptEip - offset JudgeDecryptResType
[COLOR=Red];; esi 为函数头地址 [/COLOR]
[COLOR=Red] ;; 这里不加密第一个ICON与第一个ICON GROUP
;; 在PE加载器加载时要读取这些资源
;; 否则程序会崩溃
;; 清除加密标志[/COLOR]
;xor eax, eax
mov ebx, esi
sub ebx, offset JudgeDecryptResType - offset DecryptRes_bDecrypt
;mov dword ptr [ebx], eax
[COLOR=Red] ;; ebx 为解密标志
;; edx 为解密标志的地址
;; 用两个寄存器来代替变量[/COLOR]
mov edi, dword ptr [ebp+JudgeDecryptResArg_Entry]
assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
mov eax, dword ptr [ebp+JudgeDecryptResArg_dwLevel]
cmp eax, 0
jnz ExitJudgeLevel
[COLOR=Red] ;; 显示类型[/COLOR]
mov eax, dword ptr [edi].Name1
cmp eax, RT_ICON
jnz CmpICON_GROUP
jmp ExitJudgeLevel
CmpICON_GROUP:
cmp eax, RT_GROUP_ICON
jnz CmpVERSION
jmp ExitJudgeLevel
CmpVERSION:
cmp eax, RT_VERSION
jnz DecryptData
ExitJudgeLevel:
assume eax : nothing
assume edi : nothing
pop esi
pop ebx
pop edi
pop eax
mov esp, ebp
pop ebp
retn 08h
DecryptData:
push 1
pop dword ptr [ebx]
jmp ExitJudgeLevel
EndDecryptResource:
CryptResource endp
个人觉的加密资源节在软件保护方面没有什么太大的意义。对于加密资源节最大的意义应该是对于壳加密木马的时候,有些木马将rootkit以资源的形式存放,杀毒软件会遍历资源节来寻找特征码。如果此时加密了这个。在解密时恢复,那么就可以通过杀毒软件的查杀。
...
那个资源节结构图是用EDraw画的,原文件也一并上传了。画的难看了点,见谅。。。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课