首页
论坛
课程
招聘
[原创]手工隐藏api函数调用——简单对付静态分析
2009-7-25 15:25 17906

[原创]手工隐藏api函数调用——简单对付静态分析

2009-7-25 15:25
17906
隐藏api函数调用对于对付静态分析,不用说是非常有意义的,许多加壳软件在输入表上大做文章,其中有一个重要的作用就是让破解者在得到的反汇编代码中看不到正常的api函数调用。我做一个最简单的测试,在不借助加壳软件和虚拟机保护技术的情况下,用手写代码的方式来实现隐藏api函数调用。
先看看我要保护的代码:
#include "windows.h"
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
  MessageBox(0,"Reverse Me","Test",0);
  return 0;
}

用IDA反汇编后,MessageBoxA函数的调用暴露无遗:
.text:0040102A 6A 00             push    0                     ; uType
.text:0040102C 68 2C 00 42 00    push    offset Caption        ; "Test"
.text:00401031 68 1C 00 42 00    push    offset Text           ; "Reverse Me"
.text:00401036 6A 00             push    0                     ; hWnd
.text:00401038 FF 15 94 52 42 00 call    ds:__imp__MessageBoxA@16 ; MessageBoxA(x,x,x,x)

我们的任务就是让反汇编的代码看不到 ds:__imp__MessageBoxA@16 ; MessageBoxA(x,x,x,x) 这样的提示。

1.最基本、最简单的方法:
#include "windows.h"
typedef int (WINAPI *MYFUNC)(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
  char MsgBoxA[]={0x5c,0x74,0x62,0x62,0x70,0x76,0x74,0x53,0x7e,0x69,0x50,0x00};  //字符串"MessageBoxA"的加密形式。
  char lpText[]={0x43,0x74,0x67,0x74,0x63,0x62,0x74,0x31,0x5C,0x74,0x00};  //字符串"Reverse Me"的加密形式。
  char lpCaption[]={0x45,0x74,0x62,0x65,0x00};  //字符串"Test"的加密形式。
  for(int i=0;i<strlen(MsgBoxA);i++)  MsgBoxA[i]^=0x11;  //解密字符串"MessageBoxA"
  for(i=0;i<strlen(lpText);i++)    lpText[i]^=0x11;  //解密字符串"Reverse Me"  
  for(i=0;i<strlen(lpCaption);i++)  lpCaption[i]^=0x11;  //解密字符串"Test"
  HMODULE hMod=LoadLibrary("user32.dll");
  if(hMod)
  {
    MYFUNC func=(MYFUNC)GetProcAddress(hMod,MsgBoxA); //获取MessageBoxA的函数地址。
    func(0,lpText,lpCaption,0);  //调用MessageBoxA函数。
    FreeLibrary(hMod);
  }
  return 0;
}

现在MessageBoxA函数调用处func(0,lpText,lpCaption,0),用IDA反汇编的结果为:
.text:00401172 6A 00             push    0
.text:00401174 8D 55 E0          lea     edx, [ebp+var_20]
.text:00401177 52                push    edx
.text:00401178 8D 45 E8          lea     eax, [ebp+var_18]
.text:0040117B 50                push    eax
.text:0040117C 6A 00             push    0
.text:0040117E FF 55 D4          call    [ebp+var_2C]

2.不用GetProcAddress
现在已经看不到赤裸裸的MessageBoxA了,而且IDA连个提示也不给了,但是调用的GetProcAddress函数同样是一个隐患,我们把它也隐藏起来:
。。。。。。

  MYFUNC func=NULL;
  char * pFuncName;
  HMODULE hMod=LoadLibrary("user32.dll");
  if(hMod)
  {
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
    PIMAGE_NT_HEADERS pNtHeader  = (PIMAGE_NT_HEADERS)((ULONG)hMod+pDosHeader->e_lfanew);
    PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader);
    PIMAGE_DATA_DIRECTORY pExportData = (PIMAGE_DATA_DIRECTORY)(&(pOptionalHeader->DataDirectory[0]));
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((ULONG)hMod+pExportData->VirtualAddress);
    ULONG * AddrFunctions=(ULONG *)((ULONG)hMod+pExportTable->AddressOfFunctions);
    ULONG * AddrNames=(ULONG *)((ULONG)hMod+pExportTable->AddressOfNames);
    for(i=0;i<pExportTable->NumberOfFunctions;i++)
    {
      pFuncName=(char *)((LONG)hMod+AddrNames[i]);
      if(strcmp(pFuncName,MsgBoxA)==0)
      {
        func=(MYFUNC)((LONG)hMod+AddrFunctions[i]);
        break;
      }
    }
    if(func)
      func(0,lpText,lpCaption,0);
    FreeLibrary(hMod);
  }
。。。。。。

3.SMC
现在连GetProcAddress也没有了,隐蔽性更好了,我们还想做得更隐蔽一点,用个简单的SMC:
#pragma comment(linker, "/SECTION:.text,ERW")
void Decrypt(char * start,char * end)
{  
  for(char * i=start;i<end;i++)
  {
    (*i)^=0x11;
  }
}
。。。。。。

  Decrypt((char * )401000,(char * )400000); //两个需要更正的地址参数。
  __asm inc eax  __asm dec eax  //16进制对应40 48 ,用来标记加密代码段起始地址
  HMODULE hMod=LoadLibrary("user32.dll");
。。。。。。

  __asm inc eax __asm dec eax //16进制对应40 48,用来标记加密代码段末地址
  return 0;
。。。。。。

编译后,用OD装载,查找二进制字串40 48,定位我们要加密的代码:

004011B6  |.  68 801A0600   push    61A80     //加密末地址,需更正
004011BB  |.  68 681E0600   push    61E68  //加密起始地址,需更正
004011C0  |.  E8 40FEFFFF   call    00401005   //调用Decrypt函数
004011C5  |.  83C4 08       add     esp, 8
004011C8  |.  40            inc     eax 
004011C9  |.  48            dec     eax
。。。。。

004012B6  |> \40            inc     eax
004012B7  |.  48            dec     eax

我们在汇编状态下把Decrypt函数调用的参数更正为我们所加密的代码段的起始地址和末地址

004011B6      68 B8124000   push    004012B8  //加密末地址
004011BB      68 C8114000   push    004011C8  //加密起始地址


由于这是个简单的异或运算,加密和解密算法相同。我们就来个投机的办法,将程序运行到这一句004011C5 add esp, 8 。此时Decrypt函数帮我们完成了加密,呵呵。然后复制到可执行文件-》所有修改,接着保存文件即可完成SMC加密。

到这里已经完成了一个简单的api函数隐藏,但是这些方法,主要用来对付静态分析,如果动态跟踪的话就容易原形毕露了.这是我在学习过程中的一点心得,希望看雪的朋友们能多多指教.

【看雪培训】《Adroid高级研修班》2022年春季班招生中!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (38)
雪    币: 1834
活跃值: 活跃值 (20)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
yingyue 活跃值 2009-7-25 19:31
2
0
你这样没用的, 我相信没有任何人会只用 IDA 看程序的 ,动静合一 就连 几百年前的武术都知道这个道理
人家 一个 f9 就可以看到不该看的地方
雪    币: 482
活跃值: 活跃值 (932)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2009-7-25 23:06
3
0
心得写的很好.
谢谢分享~~~
雪    币: 58
活跃值: 活跃值 (243)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
HotPower 活跃值 2009-7-25 23:09
4
0
用COM接口技术会好些的,可以给反汇编增加难度。
雪    币: 227
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
loway 活跃值 2009-7-26 01:30
5
0
如果到了最后还是完整的解密的话 那么用OD运行之后不就全都看到了吗?
雪    币: 1481
活跃值: 活跃值 (146)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
cntrump 活跃值 13 2009-7-26 09:59
6
0
加密后就不信你不解密,在你解密的时候我再K你
雪    币: 69
活跃值: 活跃值 (14)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
DebugFan 活跃值 3 2009-7-26 17:48
7
0
呵呵,我这个旨在对付静态分析.那个SMC没有嵌套,也没有Anti-Debug,要对付它,那比捏死一只蚂蚁还容易.
雪    币: 105
活跃值: 活跃值 (252)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Fido 活跃值 2009-7-28 09:50
8
0
对初学者应当很受用
雪    币: 263
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chupch 活跃值 2009-7-28 10:46
9
0
思想重要,思想重要~
雪    币: 302
活跃值: 活跃值 (45)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
HSQ 活跃值 8 2009-7-28 11:07
10
0
这种隐藏方式以前也用汇编实现过,对静态的还算有点效果,可拿OD一跟进去,或用API监视工具,最后还是会暴露无疑的。即使自己弄个该功能的引擎,其效果还不如拿VMProtect之类的加壳工具搞定了事,总之个人认为效果不是很好,没有深究的念头
雪    币: 45
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
nkspark 活跃值 3 2009-7-28 11:16
11
0
牛~~~~~~~
雪    币: 222
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yugi 活跃值 2009-7-28 11:30
12
0
学习了
还用 scm 呀
不错
雪    币: 375
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
Cyane 活跃值 1 2009-7-28 17:25
13
0
学习  想法很好
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
woami 活跃值 2009-7-28 19:55
14
0
谢谢,学习了,但是这种方法,如果软件稍微大一点会不会影响运行速度,而且编程复杂度也很高!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
月下听禅 活跃值 2009-7-28 20:19
15
0
这样感觉编程好复杂了啊。本来API编程就是隐藏底层代码的。这样的话,写代码就累死了。。。。。
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
兔兔冷 活跃值 2009-7-28 22:18
16
0
学习一下,支持了!
雪    币: 200
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jiaqiao 活跃值 2009-7-28 22:38
17
0
非常感谢贡献
雪    币: 1225
活跃值: 活跃值 (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
jackozoo 活跃值 14 2009-7-28 23:24
18
0
现在很多病毒都是这么干的, 虽然IDA看不到API调用过程, 但是如果比较有规律的话, 可以写idc来处理.
你这里因为程序较简单, 是将地址表放在局部变量内. 一般病毒要用到很多API, 一般地址表实在全局变量.
所以调用时, 大多类似一下方式:

mov R, [0040XXXX]
... ... //无关指令
...
call R

像这种就很有规律, 可以用idc处理.
雪    币: 1225
活跃值: 活跃值 (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
jackozoo 活跃值 14 2009-7-28 23:26
19
0
另外, 通过比较函数名Hash而不是函数名字串可以更节省代码空间, 也更优美.
雪    币: 208
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hardcode 活跃值 2009-7-29 09:53
20
0
如果你把要隐藏的函数的hash算出来,硬编码到程序中,查找API名字的时候,通过比较API函数名的hash值,这样是不是会增加一些调试的难度?
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mazhenxing 活跃值 2009-7-29 11:48
21
0
写的真不错。很好
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
seesth 活跃值 2009-7-29 14:45
22
0
学习了,谢谢分享。
雪    币: 1467
活跃值: 活跃值 (235)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
menting 活跃值 14 2009-7-29 15:20
23
0
不是我说LZ,你这个基本作用不大,隐藏的API只要留意一下就能看出来,前提是熟悉API啊,因为常规的一些API,看习惯了,很容易根据参数就能一眼看出来,是那个API,即使看不出来,也能知道API是那类的,如果调试的话,你那个没作用,姑且不说能不能调试,就算不能调试,这样的也可以根据整体代码的流程来看出来,比如:前面都注册窗口了,下面的个函数被LZ隐藏了,但是习惯性的就知道下面一个函数是创建窗口,在根据参数一看,几乎98%确定,我基本上拿OD看汇编,IDA只看流程,所以,LZ的方法,基本上作用不大,再说了,就算拿IDA看,IDA只是相关的参考,仔细分析一下,还是可以发现被隐藏的。

再说了,LZ这个思路到是不错的,但是,这样做如果真一个个去隐藏,确实很麻烦,而又耗时。
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
王小攀 活跃值 2009-7-29 23:44
24
0
学习了,呵呵
雪    币: 384
活跃值: 活跃值 (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Pan88168 活跃值 2009-8-1 11:20
25
0
都不看标题的..

人家说是简单对付静态分析.,不用IDA,难道还有比IDA更强的分析工具?

用OD的人都买块砖头拍自己头吧.
游客
登录 | 注册 方可回帖
返回