[原创]汇编级别--如何在函数中隐藏函数


这两天终于有点正经地写点程序了。在考虑如何对付反汇编与跟踪。
突发奇想,想出了在函数中隐藏函数这么一招。嘿嘿,似乎有点好玩。
OK,既然想在函数的隐藏函数,那么这个隐藏函数就无法像正常函数一样地定义了。
手工打造!如此如此...

 

ex_proc proc @arg
 jmp @F  
; 函数开始就跳转,给隐藏函数提供代码空间
 push ebp  ; 隐藏函数开始
 mov ebp , esp
 
; ...隐藏函数功能实现指令
 mov esp , ebp
 pop ebp
 retn  
; 隐藏函数结束
 @@:    ; 正常函数开始
  ; ...正常函数功能实现指令
 ret
ex_proc endp

 

作为一个函数的标志,我们在构造隐藏函数的时候需要加入:

push ebp
mov ebp,esp
;.....
mov esp,ebp
pop ebp
retn


吝啬地说来,如果函数不需要使用堆栈传递参数或构造局部变量的话,只需要给一个"retn"足矣。
当然,这个前提条件很苛刻,所以还是老实点加上那五行才是正经。
嗯,好。函数打造完了。那么,正常过程中我们如何使用它呢?
载入OD。看看内容:

 

00401000    .   55             push    ebp    ; 正常函数开始
00401001    .  8BEC          mov     ebp ,  esp
00401003    .  83C4 F0       add     esp ,  - 10
00401006    .  EB  17          jmp     short 0040101F
00401008   /.   55             push    ebp   ; 隐藏函数位置
00401009   |.  8BEC          mov     ebp ,  esp
0040100B  |.  6A 
00          push     0                                  ;  /Style = MB_OK|MB_APPLMODAL
0040100D  |.  6A  00          push     0                                  ;  |Title = NULL
0040100F  |.   68   33204000    push     00402033                           ;  |Text = "pig4210"
00401014   |.  6A  00          push     0                                  ;  |hOwner = NULL
00401016   |.  E8 A1000000   call    <jmp.&user32.MessageBoxA>         ;  MessageBoxA
0040101B  |.  8BE5          mov     esp ,  ebp
0040101D  |.  5D            pop     ebp
0040101E  .  C3            retn  
; 隐藏函数结束
0040101F   >   60             pushad   ; 正常函数开始
00401020    .  FF75  08        push    dword ptr  [ ebp+8 ]                  ;  /<%d>
00401023    .   68   30204000    push     00402030                           ;  |Format = "%d"
00401028    .  8D45 F0       lea     eax ,  dword ptr  [ ebp-10 ]            ;  |
0040102B   .   50             push    eax                               ;  |s
0040102C   .  E8  85000000    call    <jmp.&user32.wsprintfA>           ;  wsprintfA
00401031    .  83C4 0C       add     esp ,  0C
00401034    .  6A  00          push     0                                  ;  /Style = MB_OK|MB_APPLMODAL
00401036    .  6A  00          push     0                                  ;  |Title = NULL
00401038    .  8D45 F0       lea     eax ,  dword ptr  [ ebp-10 ]            ;  |
0040103B   .   50             push    eax                               ;  |Text
0040103C   .  6A  00          push     0                                  ;  |hOwner = NULL
0040103E   .  E8  79000000    call    <jmp.&user32.MessageBoxA>         ;  MessageBoxA
00401043    .   61             popad
00401044    .  C9            leave
00401045    .  C2  0400        retn     4

 

嘿嘿,这么一搞,OD的自动分析只能识别出我们的隐藏函数,而正常函数的外壳竟然无法分析出来。
而用IDA反汇编,IDA果然是反汇编界牛哄哄的XX。它识别出了正常函数,并把隐藏函数剥离出来放在另一边。
然而,我们的目的算是达到了,因为至少已经让cracker有点晕。
至少,他不清楚这个多出来的一段是什么意思。
言归正传。我们已经看到,隐藏函数在正常函数的位置偏移8个字节。
但是,请注意,在我们现实使用中,并不是都是8个字节,这个需要计算,最好反汇编自己跟一遍。
因为:

 

00401000    .   55             push    ebp    ; 正常函数开始,两个指令,共3B
00401001    .  8BEC          mov     ebp ,  esp
00401003    .  83C4 F0       add     esp ,  - 10   ; 分配局部变量,指令长度3B。如果分配的局部变量大的话,指令长度会达到6B
00401006    .  EB  17          jmp     short 0040101F  ; 绝对跳转2B,因为是short跳,所以指令短。
   ; 如果隐藏函数大的话,7F空间不够用,则将变成长跳转,这时指令长度会达到5B


好,现在当前函数偏移8。使用代码如下:

 lea eax , ex_proc  ; 取得ex_proc函数地址
 add eax , 8    ; 偏移8B
 call eax   ; 开始调用


...
在写这篇文章的时候我突然想到一个方法,实践了一下,成功。嘿嘿。下面再分享经验:
其实我们如果在隐藏函数开始前加一个"hidden_proc equ this byte"定义一个标记。
这样,在调用的时候就不需要计算偏移了,让编译器自己帮我们算吧,嘿嘿

 lea eax , ex_proc  ; 取得ex_proc函数地址
 add eax , hidden_proc-ex_proc   ; 编译器会帮我们计算偏移的
 call eax   ; 开始调用


好爽!
写成DLL都可以提供给外部程序调用,只是那个偏移值。。。如果你愿意,可以把这个值也exports掉。
这样,C版本如何调用应该不用我说了吧。。

目前,这个思想还有一些需要实践检验的地方。
欢迎拍砖,交流。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值