加密资源节

自研APK加固方案:从原理到实现,构建代码资源全加密防护体系 在移动应用安全领域,代码保护与反逆向是开发者面临的核心挑战。其基本原理是通过加密、混淆等技术手段,将应用的核心逻辑与资源进行隐藏,防止静态分析与动态调试。这项技术的核心价值在于显著提升应用的逆向工程门槛,保护知识产权与商业逻辑。在应用场景上,尤其适用于对安全有极致要求或需深度定制防护策略的金融、游戏及企业级应用。本文聚焦于自研APK加固方案,深入剖析如何通过自定义的加密算法与运行时Hook技术,实现对DEX字节码、资源文件及SO库的全方位加密隐藏,从而构建独特的安全壁垒,有效对抗自动化脱壳与主流逆向手段。 阅读详情

 作 者: 玩命
时 间: 2008-07-10,21:27
链 接: http://bbs.pediy.com/showthread.php?t=68262

什么是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
    ;; 计算有几个资源在当前目录下
    mov cx, word ptr [esi].NumberOfNamedEntries
    add cx, word ptr [esi].NumberOfIdEntries
    movzx ecx, cx
    ;; 这里存在着ecx个IMAGE_RESOURCE_DIRECTORY_ENTRY
    add esi, sizeof IMAGE_RESOURCE_DIRECTORY
    mov edi, esi
    assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
ResDirEntryLoop:
    ;; 打印资源层
    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:
    ;; 取出资源文件
    add eax, g_pResSection
    assume eax : ptr IMAGE_RESOURCE_DATA_ENTRY
    mov edx, dword ptr [eax].Size1
    mov eax, dword ptr [eax].OffsetToData
    ;; 转化RVA到偏移
    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
    ;; 显示类型
    mov eax, dword ptr [edi].Name1
    invoke ShowResourceType, eax
    jmp ExitJudgeLevel
JudgeLevelOne:
    cmp eax, 1
    jnz JudgeLevelTwo
    ;; 显示名称
    mov eax, dword ptr [edi].Name1
    ;; 最高位是0时表示使用ID
    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
    ;; 拷贝字符串到局部变量
    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:
    ;; 第三次是语言,这里输出语言定义的常量
    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
    ;; 计算有几个资源在当前目录下
    mov cx, word ptr [esi].NumberOfNamedEntries
    add cx, word ptr [esi].NumberOfIdEntries
    movzx ecx, cx
    ;; 这里存在着ecx个IMAGE_RESOURCE_DIRECTORY_ENTRY
    add esi, sizeof IMAGE_RESOURCE_DIRECTORY
    mov edi, esi
    assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
ResDirEntryLoop:
    ;; 加密资源层
    ;; 清除加密标志,如果是0级别则清除
    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:
    ;; 加密资源文件
    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
    ;; 转化RVA到偏移
    invoke RVA2Offset, g_pMem, eax
    add eax, g_pMem
    
    ;; 加密资源
    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
    
    ;; 不加密ICON,ICON_GROUP,还有版本信息
    ;; 在PE加载器加载时要读取这些资源
    ;; 否则程序会崩溃    
    
    mov edi, pResEntry
    assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
    mov eax, dwLevel      
    ;; 不是类型层,直接退出 
    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
    
    ;; 判断是否存在资源节
    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     ; ebx 为资源节在内存中的地址
    ;; 转变为FVA
    invoke RVA2Offset, pMem, eax
    add eax, pMem
    mov g_pResSection, eax
    
    ;; 加密资源节
    invoke EncryptResSec, eax, 0
          
    ;; 升级数据
    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]
    
    ;; 添加解密节
    invoke AddSection, pMem, NULL, g_dwDecryptResourceSize
    mov esi, eax
    assume esi : ptr IMAGE_SECTION_HEADER
    
    ;; 更新入口点与SizeOfImage
    mov edi, dwNTHeaderAddr
    assume edi : ptr IMAGE_NT_HEADERS
    
    ;; 更改资源节属性
    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 ; 可读可写可执行
    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
    
    ;; 将解密节写入
    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
    
;; ----- 解密资源节 -----
DecryptResource:
DecryptResourceStackSize    equ 10h
DecryptResource_Eip         equ -04h
DecruptResource_dwFlags     equ -08h
    push ebp
    mov ebp, esp
    sub esp, DecryptResourceStackSize
    ;; 清0堆栈
    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
    
    
    
    ;; 读取原入口点
    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
    ;; ----- 解密资源节数据 -----
    DecryptRes_dwOrigEntryAddress           dd  0
    DecryptRes_ResVA                        dd  0
    DecryptRes_bDecrypt                     dd  0
    DecryptRes_ImageBase                    dd  0
    ;; ----- 递归解密资源节的函数 -----
    
    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
        
        ;; 获取eip
        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
        ;; 计算有几个资源在当前目录下
        mov cx, word ptr [esi].NumberOfNamedEntries
        add cx, word ptr [esi].NumberOfIdEntries
        movzx ecx, cx
        ;; 这里存在着ecx个IMAGE_RESOURCE_DIRECTORY_ENTRY
        add esi, sizeof IMAGE_RESOURCE_DIRECTORY
        mov edi, esi
        assume edi : ptr IMAGE_RESOURCE_DIRECTORY_ENTRY
    ResDeDirEntryLoop:
        ;; 解密资源层
        ;; 是0级别则清除
        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:
        ;; 取出资源文件
        mov ebx, dword ptr [ebp+ResDecryptRes_Eip]
        sub ebx, offset RecDecryptRes - offset DecryptRes_bDecrypt
        mov ebx, dword ptr [ebx]
        test ebx, ebx
        jz ContinueResDeDirEntryLoop
        
        ;; ebx 不为0则解密
        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
        
        ;; 解密资源
        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
                  
    ;; ----- 判断资源类型 -----
    JudgeDecryptResType:
    JudgeDecryptResArg_Entry            equ 08h
    JudgeDecryptResArg_dwLevel          equ 0ch
        
        push ebp
        mov ebp, esp 
      
        push eax
        push edi
        push ebx
        push esi
        
        ;; 获取EIP
        call GetJudgeDecryptEip
        GetJudgeDecryptEip:
        pop esi
        sub esi, offset GetJudgeDecryptEip - offset JudgeDecryptResType
        ;; esi 为函数头地址     
      
        ;; 这里不加密第一个ICON与第一个ICON GROUP
        ;; 在PE加载器加载时要读取这些资源
        ;; 否则程序会崩溃
        
        ;; 清除加密标志
        ;xor eax, eax
        mov ebx, esi
        sub ebx, offset JudgeDecryptResType - offset DecryptRes_bDecrypt
        ;mov dword ptr [ebx], eax
        
        
        ;; ebx 为解密标志
        ;; edx 为解密标志的地址
        ;; 用两个寄存器来代替变量
        
        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
        ;; 显示类型
        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以资源的形式存放,杀毒软件会遍历资源节来寻找特征码。如果此时加密了这个。在解密时恢复,那么就可以通过杀毒软件的查杀。

资源结构解析 目录预备知识一、资源简介二、eXeScope实验目的实验环境实验步骤一实验步骤二实验步骤三 预备知识 一、资源简介 资源是PE文件中非常重要的组成部分,几乎所有的PE文件都包含有资源数据,不过与输入表和输出表相比,资源的组织方式就复杂多了。 资源数据通常存放在PE文件的.rsrc节区中,不过正确找到资源段的方式是通过数据目录表的第三项来获取。 二、eXeScope 资源可以进行定制和修改,如更改字体、对话框,增加按钮、菜单等。如果大家有Visual C++/Visual Studio开发经验,那么一定对其修 阅读详情

相关推荐

【网络安全】Xred蠕虫的Delphi实现与COM组件修复技术解析

本文深入解析了Xred蠕虫病毒的Delphi实现与COM组件修复技术,详细介绍了其感染机制、系统兼容性处理及文档感染原理。通过开发图形化修复工具,提供了EXE和XLSX文件的两种修复方案,并分享了防御建议与最佳实践,帮助提升网络安全防护能力。

weixin_29219189的博客 537

C/C++ 对代码节的动态加解密

加壳的原理就是加密或者压缩程序中的已有资源,然后当程序执行后外壳将模拟PE加载器对EXE中的区块进行动态装入,下面我们来自己实现一个简单的区块加解密程序,来让大家学习了解一下壳的基本运作原理。运行后对.text节进行动态解密,然后一个jmp跳转到程序的OEP位置即可,这也就是壳的基本原理。下一步就是将.text节进行加密了,这里为了简单我使用的是异或加密,如下是加密前的机器码。使用我们编写的工具进行加密,传入两个参数,一个是文件,一个则是加密密钥。加壳的首要目标是要创建一个具有可写属性的新节。

微软技术分享 1万+

别再只盯着AES了!聊聊STM32上那些冷门但好用的轻量级加密算法(附代码)

本文探讨了STM32上五种冷门但高效的轻量级加密算法,包括ChaCha20、Speck、Ascon、PRESENT和SPARKLE,适用于资源受限的嵌入式设备。通过对比AES-256的资源占用和性能,展示了这些算法在Flash、RAM占用和加密速度上的优势,并提供了实战代码和选型建议,帮助开发者在智能家居、可穿戴设备等场景中实现安全与性能的平衡。

weixin_29327525的博客 343

手动添加PE文件数字签名信息及格式详解图之下(历史代码,贴出学习)

手动添加PE文件数字签名信息及格式详解图之下

关注互联网安全的小虾米一枚 5816

真正的JavaScript加密和网页资源加密系统,从原理到实现

网站作为网民获取信息的主要来源之一,基于Html5的建站服务和应用越来越多,而Html5存在一个关键问题: 网页内的资源(包括了javascript、文字、图像等)可以通过非常简单的方式获取! 目前网络上提供了各种针对javascript(简称js)的加密手段,主要还是以混淆,Base64,去逻辑化等手段进行保护。先不说此类的加密是否安全,但是针对内部链接、文字、图像相关的数据并没有合理的加密手段。这个一方面的原因是js需要浏览器的javascript引擎完成执行,直接密码后的js是无法运行的,于是就出

王杰林(编码技术)的博客 6883

一文带你弄懂thermal governor IPA

当current temp < target temp时,使用k_pu,当current temp >= target temp时,使用k_po。如果current_temperature = switch_on_temp时,则k_p = k_pu,这时Pmax。如果current_temperature = target_temp时,则k_p = k_po,这时Pmax。2、解析dts,获得switch_on_temp和target_temp。3、初始化k_pu/k_po/k_i/k_d的常数。

yxw0609131056的博客 1247

java实现使用 "DESede" 对称加密的 加解密工具类

前言: Java实现 "DESede" 对称加密; 前提: 在代码运行前,需要提前将一个依赖导入到项目中 pom.xml 中,使用这个依赖中的base64进行编解码; <!-- base64编码使用 --> <dependency> <groupId>commons-codec</groupId> <ar...

木子雷的博客 1761

uniapp 开发微信小程序请求问题 , 真机调试正常,开发工具正常,但是使用扫码预览接口都是不通的,发布到体验版也是请求失败

uniapp开发小程序体验版接口请求失败(真机可以)

weixin_60408555的博客 3954

AtomLdr资源节区处理技术:自定义代码如何安全提取加密payload

AtomLdr是一款具有高级规避功能的DLL加载器,其核心能力之一是通过资源节区安全管理和提取加密payload。本文将深入解析AtomLdr如何利用Windows资源系统实现payload的加密存储与安全提取,为开发者提供规避检测的关键技术思路。 ## 资源节区基础:Windows可执行文件的隐藏存储区 Windows可执行文件(.exe/.dll)的资源节区(Resource Sectio

gitblog_01134的博客 1001

YOLO26改进策略【Head】| (独家改进)轻量化检测头:利用 EfficientNet 中的移动倒置瓶颈模块 MBConv 改进检测头

本文记录的是基于移动倒置瓶颈 MBConv 的 YOLO26 的检测头轻量化改进方法研究。采用了独特的倒置瓶颈结构,通过的操作以及,在高效提取特征的同时极大地降低了计算量。本文将的设计优势融入j检测头中,使其在目标检测任务中不仅能够更精准地识别各类目标,还能在计算资源有限的情况下快速响应,展现出更为卓越的实时检测能力。EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks的实现代码如下: 首先在代码中加入如下代码: 其

Limiiiing的博客 291

Google Earth Engine(GEE)——使用归一化燃烧指数 (NBR) 绘制地表烧伤严重程度图

归一化燃烧指数(Normalized Burn Ratio, NBR)是一种遥感指标,用于评估野火或烧伤地面后的植被恢复情况。NBR能增强较大范围的火灾区域,如大于200公顷。它是通过比较远红外波段 (SWIR) 和近红外波段 (NIR) 的反射率来计算的。SWIR波段测量烧伤地面的反射率,NIR波段测量没有受到烧伤影响的植被的反射率。NBR的计算公式为:NBR =(NIR-SWIR)/(NIR + SWIR)。其中,NIR为近红外波段,SWIR为短波红外波段。

此星光明博客 3466

(转)如何实现word文档与exe文件的捆绑?

作者:coleak链接:https://www.zhihu.com/question/593440315/answer/3456418014来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

m0_38107106的博客 785

CLASSB类移植(满足IEC 60730-1和60355-1标准)

针对软件认证需要满足IEC 60730-1和60335-1标准,ST公司专门提供的软件扩展包X-CUBE-CLASSB,它包含自测库和文档,支持多种STM32系列芯片,通过预集成测试库和标准化流程,帮助开发者快速满足国际安全标准,适用于家电、工业控制等高可靠性场景。ClassB软件包程序检测内容分为两个主要部分:启动时的自检和运行时的周期自检,MCU在上电的时候会进行复位启动,在启动完成以后会进行运行自检。

m0_61973119的博客 1402

恶意代码分析实战第13章实验

Lab13-1 1. 比较恶意代码中的字符串与动态分析提供的有用信息,基于这些比较,哪些数据可能被加密? string查看Lab13-01.exe字符串注意到有http字符串,并且%s表示有输出的值。 利用火绒剑监控Lab13-01.exe,可以看到文件正在访问www.practicalmalwareanalysis.com/aGFueHUtUEM=/ 推测两个%s表示的正是www.practicalmalwareanalysis.com和aGFueHUtUEM=,但在查看Lab13-01

weixin_41487541的博客 456

【Unity】 预制体Prefab使用说明

在 Unity 中,Prefab 是一个可以预先制作并重复使用的 GameObject 或组件集合,Prefab 中的 GameObject 可以有子对象和其他组件。

灵境引路人 2852

静态时序分析—伪路径(set_false_path)

set_false_path应用场景

m0_61544122的博客 2万+

浅谈捆绑免杀技术

文件捆绑免杀

记录学习,一起进步 874

在blender中安装vtk插件

Blender 是一个开源的、功能强大的3D计算机图形软件,广泛用于创建动画片、视觉效果、艺术作品、3D打印模型、互动3D应用程序和视频游戏。Blender 是由 Blender 基金会开发和维护的,具有丰富的功能和灵活的扩展性。在github上下载zip插件。

如果想成为中心,那么就到中心去吧。 294

植物大战僵尸pak资源文件分析

首先,该pak文件经过xor 0xf7加密,所以需要逐字节异或0xf7来解密pak文件。 (这个0xF7密钥是我尝试出来的,我写程序生成了xor 0x00--0xff的文件,发现密钥为0xF7) 之后,文件分为两部分,前半部分为资源文件描述结构集合。 结构: 标记 1字节(0x0是文件,0x80文件结束) 文件名长度 1字节 文件名...

t225com 1478

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

RPG Maker MV/MZ资源提取与格式转换工具:解密加密游戏文件的技术指南

在游戏开发与资源管理过程中,开发者常面临加密资源无法直接查看的问题。RPG Maker MV/MZ文件解密工具通过技术手段,为合法资源检查与备份提供解决方案。该工具支持图片与音频文件的解密与重新加密,适用于资源版权验证、项目迁移与二次开发场景。 ### 核心能力矩阵 - **无密钥图片恢复**:通过特殊算法直接处理加密图片 - **全类型文件解密**:支持图片与音频格式的完整解密 - **双向格

gitblog_00184的博客 452

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

三步提取 RPG Maker 游戏资源:从 Game.rgss3a 到可编辑项目

想修改一款 VX Ace 游戏里的文本,却发现游戏目录里只有一个二进制的 Game.rgss3a,任何编辑器都打不开。这类文件是 RPG Maker 打包数据时做的 RGSS 加密档案。RPG Maker Decrypter 是一个开源的 RGSS 解密工具:它能解密 .rgssad(XP)、.rgss2a(VX)、.rgss3a(VX Ace)三种加密档案,完成游戏资源提取,并可生成对应版本的工

gitblog_00943的博客 183

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

关于exe或dll文件中的字符串资源

资源在WindowsGUI的程序中随处可见,这也是微软为了方便把界面和逻辑分开的优秀策略。所谓的资源就是一些用于描述界面或其他特征的说明性字符,它们有固定的格式。这点与HTML有相似之处。而微软提供了处理这些资源描述字符的函数,并上升到Win32API的高度。资源有两种存在形式,一是编译之前,此时的资源被存放到.rc文件(此文件为纯文本文件)中,在程序编译的时候,资源编译器rc.exe把.rc文件

smstong的成长轨迹 5932

恶意代码分析实战 10 数据加密

使用WireShark进行动态分析。有一串字符看起来像是加密的。使用Strings分析一下。发现疑似Base64的存在痕迹。没有发现上面看到的疑似加密的字符串和网址。可能是加密了。使用IDA查找所有xor位置。这里面唯一看着像是加密的是这行命令。:::info:::对字符进行了xor的3Bh操作。交叉引用,进入函数调用处。对资源进行了很多操作。我们怀疑加密数据就在资源节中。使用ResourceHacker查看。使用WinHex进行修改。是一个网址。

农夫果园好好喝的博客 1222

cocos creator 图片资源加密

cocos creator 没有对资源进行加密,打包资源的资源很容易被扒,需要自己实现一套加密方式。这里简单记录下资源的加密方式。 加密 加密算法: XOR 时机:在资源压缩打包完成之后 加密工具: python脚本 def encrypt(content): """ 加密内容 :param content: 加密密的字符串 :return: 加密之后的字符串 ...

寒风的技术博客 8315
上一篇: fs TIB TEB PEB
下一篇: 完整可编译NT4's NTFS源码(可稳定替换xp原版ntfs.sys
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值