安全中国首页 > 文章中心 > 加密算法
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

通用且简单的扩充和改造PE中的call的功能的方法

更新时间:2008-1-27 0:12:09
责任编辑:阿loosen
热 点:
技术基础:会编写加壳程序、了解PE结构、X86指令系统。
开发工具:MASM、VC++

1、我们有时候在改造一个PE的时候,对其中的某些call要做大量的改动,这时
候,往往通过手动增加一个节,在这个节中完成这个call的改造,再返回原来的地方继续执行。此法虽然可行,但工作量实在太大,且调试十分不方便。

2、“通用简单的方法”之实现原理:
    使用jmp far address 和 call far address的机器码长度相同,且仅仅第一字节不同的原则,jmp第一字节是0xE9,而call第一字节是0xE8,后面4字节相同。
    这种方法就是:通过给PE加个小壳,同时在加壳的时候,将PE中要改造的call 修改成调用外壳中的call,在外壳中的call中调用原来PE中的call,而外壳中的call我们在编写的时候较容易实现功能扩充和改造。
    在外壳中的call中,我们有两种扩充功能的方式:
    (1)在调用原来PE中的call之前扩充功能;
    (2)在调用原来PE中的call之后扩充功能;
    扩充功能可以直接在外壳call中实现,但较难调试和复杂。
    简单通用的方法是这个外壳中的新call仅仅完成:
        1、加载一个外部补丁DLL;
        2、调用这个外部补丁DLL中的函数,完成原来PE中的call的功能扩充和改造。
        3、调用原来PE中的call的;
    是先调用原来PE中的call还是后调用,视具体需要决定。这样我们就可以很简单的写扩充的功能代码了,因为这个外部补丁DLL可以用高级语言来写,且调试十分简单。

3、外壳中函数的具体实现:
    (一) 首先,在外壳中设定几个变量:
    (1) 保存外部DLL的各个函数地址的变量(DWORD):
        pfnExtPatchFun_1--pfnExtPatchFun_n,n为多大具体看要改造PE中几个函数。
    (2) 保存原来PE中的call的“地址差”变量(DWORD):
        dwOrgCallDifference_1--dwOrgCallDifference_n,n为多大具体看要改造PE中几个函数。
        dwOrgCallDifference_x = 原来call的机器码的后4个字节(双字)。
    (3) 保存原来PE中的call的RVA地址的变量(DWORD):
        dwOrgCallRVA_1--dwOrgCallRVA_n,n为多大具体看要改造PE中几个函数。
    (4) 保存外部DLL的hModule的变量(DWORD):
        hExtPatchDll。
    ;-----------------------------------------------------------------
    举例说明:
      如:原来PE的ImageBase=0x00400000,且有下面代码(IDA显示):
          .
          .
          004010CB 50                push    eax
          004010CC 57                push    edi
          004010CD E8 CE 08 00 00    call    sub_4019A0 ;需要改造的call,注意机器码后4字节
          004010D2 85 C0             test    eax, eax
          .
          .
      则:dwOrgCallRVA_1 = 004010CD - 0x00400000 = 0x000010CD
          dwOrgCallDifference_1 = 0x000008CE
   ;------------------------------------------------------------------
   ;
   (二) 在外壳程序中编写这些call,需要改造几个函数,就有几个call,格式如下:
;*****************************************************************************
;---------------------------------------------------;
; 外壳中的call,用于替换原来PE中的call               ;
;---------------------------------------------------;
align 4
wjq_API_SMC_Label_1:
GeneralPEShellCall_1    proc
;{
    ;原PE中的call的入口参数,我们通过堆栈传递到Dll中的新call,此时需注意EBP在本call中不要改变。
    @nPara1 EQU [ebp+0ch] ;原来PE中的Call的参数,也可以通过esp取得
    @nPara2 EQU [ebp+8h]
    ;
    pusha
    call GetPatchDllFunctions ;获取外部DLL中的所有函数地址并保存
    call GetAddressDifference ;获取地址差
    .if [pfnExtPatchFun_1+eax] != 0  ;如果功能函数1实现了,就调用
       push  @nPara1 ;原来PE中的Call的参数
       push  @nPara2
       call  [pfnExtPatchFun_1+eax] ;调用外部DLL中的补丁call
    .endif
    ;------------调用原来的call-------------------------
    call GetAddressDifference ;获取地址差
    lea esi,[TempCall_1+eax]  ;现在call的VA
    sub esi,[Image_Base+eax]  ;转换成RVA
    sub esi,[dwOrgCallRVA_1+eax] ;减去原来PE中的call的RVA = 两个call的地址差
    ;
    mov ebx,[dwOrgCallDifference_1+eax]  ;原来call xxxxxxxx 指令的偏移差
    .if ebx < 0  ;负数,原来call向上调用
        add ebx,esi
    .else        ;正数,原来call向下调用
        sub ebx,esi
    .endif
    ;
    mov  [TempCallDifference_1+eax],ebx  ;修正后的差值
    popa
    ;

1 2 下一页

 
相关文章
一日一文章
 
一日一软件
一日一动画