首页
社区
课程
招聘
[成果6.2]软件保护壳技术专题 - 加密引入表
发表于: 2008-6-23 05:18 35154

[成果6.2]软件保护壳技术专题 - 加密引入表

2008-6-23 05:18
35154

导入表的加密应该是壳对应用程序加密时最重要的部分了。首先我们先了解一下怎样寻找引入表,并列出其中的导入的函数与DLL命。其次,进行讲解如何加密引入表。最后,讲解在我们自定义的节表中恢复引入表并重定位函数地址。

1.寻找引入表
在IMAGE_NT_HEADERS结构中的OptionalHeader字段中有一组数据目录,数据目录数组的第二个元素就是引入表的目录索引。
数据目录的结构是这样的
IMAGE_DATA_DIRECTORY STRUCT
  VirtualAddress dd ?
  isize dd ?
IMAGE_DATA_DIRECTORY ENDS
VirtualAddress 是此表的RVA,也就是相对于模块加载的偏移量,此地址指向一个由IMAGE_IMPORT_DESCRIPTOR结构组成的数组。
isize 是此表的大小
我们利用以下算法寻找引入表
1.从 DOS header 找到 PE header
2.从 数据目录中 读取 data directory 的地址。 第二个索引就为引入表的地址。
3.IMAGE_DATA_DIRECTORY的虚拟地址偏移转化为文件偏移
4.文件偏移加上文件映射基址就为引入表的地址
寻找到引入表后,接下来的工作就是展开引入表,此时的指针指向一个IMAGE_IMPORT_DESCRIPTOR结构的数组,我们可以认为一个IMAGE_IMPORT_DESCRIPTOR结构就是一个DLL,如果你的程序引用了5个DLL那么你的程序用就有5个IMAGE_IMPORT_DESCRIPTOR结构,并且这个数组以一个全0的IMPORT_IMPORT_DESCRIPTOR为结束。为了让读者好理解在以下称IMAGE_IMPORT_DESCRIPTOR为DLL结构。
对于加密导入表最重要的有三个属性,Name1,OriginalFirstThunk,FirstThunk。
Name1也是一个偏移量,指向这个DLL的DLL字符串的内存偏移。
OriginalFirstThunk与FirstThunk两个字段也同属于指针类型的。并且在文件中都指向一个位置。当加载到内存时,OriginalFirstThunk还指向原来指向的地方,FirstThunk指向一个API函数的地址的数据。(由PE加载器帮助定位并修改的)
在文件中,OriginalFirstThunk指向一组地址的偏移,这个地址偏移被称为IMAGE_THUNK_DATA
这个偏移值指向一组IMAGE_IMPORT_BY_NAME结构的数组。这个结构读者可以认为是这个DLL文件中的API。有几个API代表有几个这样的结构。
IMAGE_IMPORT_BY_NAME STRUCT
  Hint dw ?
  Name1 db ?
IMAGE_IMPORT_BY_NAME ENDS
Hint:代表此API是DLL中的第几个函数
Name1:为此API的名字,最后以NULL结尾。我们加密API的名字就是加密Name1的字段。
另一个FirstThunk如同复制一样也一模一样的指向了与OrigFirstThunk一样的地方。但是当文件加载到内存中后,FirstThunk会指向函数的地址。这个转换由PE加载器加载。
列出引入表代码如下

ListIID proc pFilename : LPSTR
    ;; map file to memory
    LOCAL hFile : HANDLE
    LOCAL hMap : HANDLE
    LOCAL pMem : LPVOID
    LOCAL dwNTHeaderAddr : DWORD
    LOCAL szTmpBuf[MAX_PATH] : BYTE
    
    ;; 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 
    invoke GetFileSize, hFile, NULL
    .IF eax == 0
        invoke CloseHandle, hFile  
        jmp GetFileSizeFailed
    .ENDIF  
    
    ;; create memory map
    xor ebx, ebx     
    invoke CreateFileMapping, hFile, ebx, PAGE_READWRITE, ebx, eax, ebx
    .IF eax == 0
        invoke CloseHandle, hFile
        jmp CreateMapFailed                
    .ENDIF
    mov hMap, eax
    ;; map file to memory
    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                               
    ;; 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
    mov dwNTHeaderAddr, esi
    
    [COLOR=Red];; 寻找引入表[/COLOR]
    assume esi : ptr IMAGE_NT_HEADERS
    mov eax, dword ptr [esi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT * sizeof IMAGE_DATA_DIRECTORY].VirtualAddress
    [COLOR=Red];; 将内存偏移转换为文件偏移,再加上文件头的内存映射就等于引入表在文件的地址了[/COLOR]
    invoke RVA2Offset, pMem, eax
    xchg ebx, eax
    add ebx, pMem
    assume ebx : ptr IMAGE_IMPORT_DESCRIPTOR
    [COLOR=Red];; 这里直到一个全0的IMAGE_IMPORT_DESCRIPTOR结构为结束
    ;; 这里判断Name1是否为NULL[/COLOR]
    ListIIDLoop:
        mov eax, dword ptr [ebx].Name1
        test eax, eax
        jz EndListIIDLoop
        [COLOR=Red];; 此时eax指向一个DLL名字的RVA,我们将RVA转换为文件的偏移[/COLOR]
        invoke RVA2Offset, pMem, eax
        [COLOR=Red];; 文件的偏移加上文件的起始指针就为文件中的地址[/COLOR]
        add eax, pMem
       [COLOR=Red] ;; 打印DLL名[/COLOR]
        invoke PrintLine, offset g_szOutFormat, offset g_szOutLine        
        invoke PrintLine, offset g_szOutFormat, eax
        invoke PrintLine, offset g_szOutFormat, offset g_szOutLine
        [COLOR=Red];; 检查OriginalFirstThunk是否为0。如果为0则使用FirstThunk [/COLOR]       
        mov edx, dword ptr [ebx].OriginalFirstThunk
        test edx, edx
        jnz UseOrignalFirstThunk
        mov edx, dword ptr [ebx].FirstThunk
    UseOrignalFirstThunk:        
       [COLOR=Red] ;; 转换RVA转换文件偏移[/COLOR]
        invoke RVA2Offset, pMem, edx
        add eax, pMem
        mov edx, eax
    DisplayApiName:
        [COLOR=Red];; 查看edx的最高位是否是1确定是否以序数引出[/COLOR]
        test dword ptr [edx], IMAGE_ORDINAL_FLAG32
        jnz DisPlayOrd
        [COLOR=Red];; 这里edx指向IMAGE_IMPORT_BY_NAME结构的RVA,继续将它转换[/COLOR]
        mov eax, dword ptr [edx]
        invoke RVA2Offset, pMem, eax
        add eax, pMem
        assume eax : ptr IMAGE_IMPORT_BY_NAME
        [COLOR=Red];; 打印API字符串,将Name1的地址设置给eax寄存器[/COLOR]
        lea eax, [eax].Name1
        invoke PrintLine, offset g_szOutFormat, eax
        jmp NextAPI
        DisPlayOrd:
       [COLOR=Red] ;; 取出序数,低2个字节为序数[/COLOR]
        mov eax, dword ptr [edx]
        and eax, 0FFFFh        
        invoke PrintLine, offset g_szOutOrdFormat, eax
    NextAPI:
        [COLOR=Red];; 取下一个IMAGE_THUNK_DATA的值[/COLOR]
        add edx, 04h
        [COLOR=Red];; 直到edx指向一个0[/COLOR]
        mov eax, dword ptr [edx]
        test eax, eax
        jnz DisplayApiName
        [COLOR=Red];; 指向下一个DLL[/COLOR]
        add ebx, sizeof IMAGE_IMPORT_DESCRIPTOR
        jmp ListIIDLoop
    EndListIIDLoop:   
LogicShellExit:
    ;; close handle & write it
    invoke UnmapViewOfFile, pMem
    invoke CloseHandle, hMap
    invoke CloseHandle, hFile
    assume ebx : nothing
    assume esi : 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   
ShowErr:
     invoke MessageBox, NULL, eax, offset g_szErr, MB_ICONERROR
     jmp LogicShellExit
ListIID endp
IID_PRIVATE_DATA struct
    Name1                   dd  0
    OriginalFirstThunk      dd  0
    FirstThunk              dd  0
IID_PRIVATE_DATA ends

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 8
支持
分享
最新回复 (63)
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
2
列出引入表的附件。。。
上传的附件:
2008-6-23 05:19
0
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
3
晚上凌晨写完的 当时有些晕了。如果有错误 希望大家谅解。。。
2008-6-23 05:24
0
雪    币: 239
活跃值: (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
4
So strong big
首先跑来顶
2008-6-23 07:04
0
雪    币: 381
活跃值: (140)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
5
一篇文章两种风格
这个能写好的,的确是好文
2008-6-23 07:42
0
雪    币: 266
活跃值: (60)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
6
支持玩命,强悍啊
2008-6-23 08:05
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
进来学习,谢谢
2008-6-23 08:36
0
雪    币: 321
活跃值: (271)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
8
不得不顶啊。
2008-6-23 08:47
0
雪    币: 1140
活跃值: (4217)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
9
这个要多看几遍

因为有点高
2008-6-23 09:09
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
10
太玩命了
2008-6-23 09:18
0
雪    币: 200
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
强~~~好东西
2008-6-23 09:37
0
雪    币: 193
活跃值: (26)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
12
好文  顶起
2008-6-23 09:42
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
13
要是用C写就好了。asm看着真累
2008-6-23 11:09
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
顶起,  太勤快了!
2008-6-23 13:41
0
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
15
没这个限制的,你可以重复上传n个。

还真玩命了,置顶几天鼓励一下。
2008-6-23 14:01
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ltr
16
初学者难以明白。
2008-6-23 15:04
0
雪    币: 201
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
讲的很清楚``辛苦了``
2008-6-23 15:37
0
雪    币: 716
活跃值: (162)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
18
拼 命 三郎
2008-6-23 16:59
0
雪    币: 197
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
真是太详细了啊,好啊,学习一下
2008-6-23 17:11
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
20
好文啊。先收藏,以后慢慢领会。

加声望表示感激之情。
2008-6-23 17:18
0
雪    币: 129
活跃值: (53)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
21
好文啊 写得真不错
2008-6-23 20:40
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
写的好,学习了
2008-6-23 22:57
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
23
关注后面的,asm 看起来不是那么习惯

保存起来打包成一个 CHM
2008-6-23 23:28
0
雪    币: 440
活跃值: (737)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
24
谢谢分享
写的不错
2008-6-23 23:31
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
先顶再看  并做个标记
2008-6-24 08:59
0
游客
登录 | 注册 方可回帖
返回
//