破解狼人 发表于 2010-10-31 23:19:10

OD与IDA联合逆向还原C程序

【文章标题】: OD与IDA联合逆向还原C程序 !
【文章作者】: 莱莉
【软件名称】: C程序
【软件大小】: 28.0 KB
【下载地址】: 见以下附件
【编写语言】: Microsoft Visual C++ 6.0
【使用工具】: PEID,OD,IDA
【操作平台】: D-Windows XP3
【程序介绍】: 供大家学习交流的小程序;
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【分析前闲谈】
--------------------------------------------------------------------------------
今天无意思中在网上发现一个有趣的注册表修改程序,于是就用PEID查查看看结果发现是C写的.然后用

OD加载看看程序写的相当的简练,再用IDA反汇编一下大部关键代码都有.于是便斗胆写此分析过程来与大

家共享,写得不好希望大家不要见笑啊!
--------------------------------------------------------------------------------
一、用PEID对程序进行查壳 → Microsoft Visual C++ 6.0 ,无壳程序啊!麻醉都不用打来真接来动手

术吧!

二、用OD载入程序进行分析。

载入OD后运行程序,插件->查找ASCII.发现有很明显的字符串提示(哈哈),然后追踪到这里(004011BE),

我们可在段首下个断开始调试,经过几次调试后发现程序的实现部分在从(004010C0)开始的,于是我们就从

这里下断调试,不过在调试时最好用插件先分析一下,这样我们就能更好的看清每个API的参数了.

--------------------------------------------------------------------------------004010C0/$51               push ecx

004010C1|.56               push esi

004010C2|.57               push edi

004010C3|.68 70614000      push savereg.00406170                  ;



sebackupprivilege (宏的指令)

004010C8|.E8 33FFFFFF      call savereg.00401000                  ;提权CALL;

004010CD|.8B35 04504000      mov esi,dword ptr ds:[<&ADVAPI32.RegOpen>;



ADVAPI32.RegOpenKeyExA (打开注册表函数)

004010D3|.83C4 04            add esp,4

004010D6|.8D4424 08          lea eax,dword ptr ss:

004010DA|.50               push eax                                 ; /pHandle

004010DB|.68 3F000F00      push 0F003F                              ; |Access =



KEY_ALL_ACCESS

004010E0|.6A 00            push 0                                 ; |Reserved = 0

004010E2|.68 30614000      push savereg.00406130                  ;



|software\microsoft\windows nt\currentversion\winlogon\notify

004010E7|.68 02000080      push 80000002                            ; |hKey =



HKEY_LOCAL_MACHINE

004010EC|.FFD6               call esi                                 ; \RegOpenKeyExA

004010EE|.85C0               test eax,eax

004010F0|.74 13            je short savereg.00401105                ;不成功就失败;

004010F2|.68 18614000      push savereg.00406118                  ;can't get key



handle\n

004010F7|.E8 14010000      call savereg.00401210

004010FC|.83C4 04            add esp,4

004010FF|.33C0               xor eax,eax

00401101|.5F               pop edi

00401102|.5E               pop esi

00401103|.59               pop ecx

00401104|.C3               retn

00401105|>8B4C24 08          mov ecx,dword ptr ss:

00401109|.6A 00            push 0                                 ; /pSecurity =



NULL

0040110B|.68 08614000      push savereg.00406108                  ; |c:\saved.hiv

00401110|.51               push ecx                                 ; |hKey

00401111|.FF15 08504000      call dword ptr ds:[<&ADVAPI32.RegSaveKey>; \RegSaveKeyA (备



件注册表)

00401117|.85C0               test eax,eax

00401119|.74 1E            je short savereg.00401139

0040111B|.68 EC604000      push savereg.004060EC                  ;can't dump



service info\n

00401120|.E8 EB000000      call savereg.00401210

00401125|.8B5424 0C          mov edx,dword ptr ss:

00401129|.83C4 04            add esp,4

0040112C|.52               push edx                                 ; /hObject

0040112D|.FF15 24504000      call dword ptr ds:[<&KERNEL32.CloseHandl>; \CloseHandle (关



闭句柄)
复制代码--------------------------------------------------------------------------------
调试时在(004010C3)里程序传递了一个sebackupprivilege (宏的指令)参数,给(004010C8)这个CALL.我

跟进去看了看,再百度一下终于知道这是个提权CALL来的.是为以下RegSaveKeyA (备件注册表)做准备.

--------------------------------------------------------------------------------00401139|> \68 E4604000      push savereg.004060E4                        ;saved!

0040113E|.E8 CD000000      call savereg.00401210

00401143|.8B4424 0C          mov eax,dword ptr ss:

00401147|.8B3D 24504000      mov edi,dword ptr ds:[<&KERNEL32.CloseHandle>] ;



kernel32.CloseHandle

0040114D|.83C4 04            add esp,4

00401150|.50               push eax                                       ; /hObject

00401151|.FFD7               call edi                                       ;



\CloseHandle

00401153|.68 D0604000      push savereg.004060D0                        ;



serestoreprivilege (恢复注册表宏)

00401158|.E8 A3FEFFFF      call savereg.00401000

0040115D|.83C4 04            add esp,4

00401160|.8D4C24 08          lea ecx,dword ptr ss:

00401164|.51               push ecx

00401165|.68 3F000F00      push 0F003F

0040116A|.6A 00            push 0

0040116C|.68 30614000      push savereg.00406130                        ;



software\microsoft\windows nt\currentversion\winlogon\notify

00401171|.68 02000080      push 80000002

00401176|.FFD6               call esi

00401178|.85C0               test eax,eax

0040117A|.74 13            je short savereg.0040118F

0040117C|.68 B8604000      push savereg.004060B8                        ;can't



open service key\n

00401181|.E8 8A000000      call savereg.00401210

00401186|.83C4 04            add esp,4

00401189|.33C0               xor eax,eax

0040118B|.5F               pop edi

0040118C|.5E               pop esi

0040118D|.59               pop ecx

0040118E|.C3               retn

0040118F|>8B5424 08          mov edx,dword ptr ss:

00401193|.8B35 0C504000      mov esi,dword ptr ds:[<&ADVAPI32.RegRestoreKey>;



ADVAPI32.RegRestoreKeyA

00401199|.6A 08            push 8                                       ; /Flags = 8

0040119B|.68 AC604000      push savereg.004060AC                        ;



|infect.hiv

004011A0|.52               push edx                                       ; |hKey

004011A1|.FFD6               call esi                                       ;



\RegRestoreKeyA (备份注册表API)

004011A3|.85C0               test eax,eax

004011A5|.74 12            je short savereg.004011B9

004011A7|>8B4424 08          /mov eax,dword ptr ss:

004011AB|.6A 08            |push 8

004011AD|.68 AC604000      |push savereg.004060AC                         ;



infect.hiv (要恢复注册表文件)

004011B2|.50               |push eax

004011B3|.FFD6               |call esi

004011B5|.85C0               |test eax,eax

004011B7|.^ 75 EE            \jnz short savereg.004011A7

004011B9|>68 00100000      push 1000                                    ; /Style =



MB_OK|MB_SYSTEMMODAL

004011BE|.68 A4604000      push savereg.004060A4                        ; |哈哈

004011C3|.68 70604000      push savereg.00406070                        ; |请查看



notifydll项,如果变更就是成功拉~点击确定恢复

004011C8|.6A 00            push 0                                       ; |hOwner =



NULL

004011CA|.FF15 C0504000      call dword ptr ds:[<&USER32.MessageBoxA>]      ;



\MessageBoxA

004011D0|.8B4C24 08          mov ecx,dword ptr ss:

004011D4|.6A 08            push 8

004011D6|.68 08614000      push savereg.00406108                        ;



c:\saved.hiv 恢复后再还原原来的SAVED注册表;

004011DB|.51               push ecx

004011DC|.FFD6               call esi
复制代码--------------------------------------------------------------------------------

当我们成功备份了saved.hiv注册表文件后,程序就再次提权恢复infect.hiv这个文件.此时我们先不要

那么手痒去按那个BOX按钮,到注册表software\microsoft\windows nt\currentversion\winlogon\notify

项看看.那里就多了个vdplugin项而且里面还有不少项值,当我们再按BOX铵钮时程序就再次恢复saved.hiv

OK,整个程序大至就是这样了.现在我们要是想还原一份程序的源码,那该怎么办呢?当然我们可以去百记搜

API再一个个慢慢的重写,不过这样的工作量也太大了.现在就请出我们的静态反编译之王IDA出来吧!正所

谓"有IDA出场,就好快会收场."IDA载入后我们可以发现里面有好多C中常用的语句,其中最引人入眼的是在

右手边能看到一个sub_401000和_main函数.那么我们就先来双击入sub_401000看看,F5后看到这个是我们

的提权CALL._main那就不要说了玩过C的人都知道这是它的主函数了通通copy下来粘贴在我们最常用的编

译器Microsoft Visual C++ 6.0 中,编译->连接下发现有错误提示.看原来是BOX函数出了乱码了,自己修

改下就没错误提示了,运行下和原版是不差上下了,不过就是停在Saved!下.于是我们下断调试下发现程序

这句出问题了:

while ( RegRestoreKeyA(hObject, "infect.hiv", 8u) );

懂得C的人都知道这样就陷入了死循环当中了程序没有结束条件,那我们再来改改吧!

while ( i<5 )
                  {
                        RegRestoreKeyA(hKey, "infect.hiv", 8u);
                        ++i;
                  }
      }      
MessageBoxA(0, "请查看notifyDLL项,如果变更就是成功拉~点击确定恢复","哈哈",0);
while ( i<10)
                  {
                        RegRestoreKeyA(hKey, "C:\\Saved.hiv", 8u);
                        ++i;
                  }

给它加个结束条件就修复了这个BUG了,再运行下你会发现和原版的根本没什么两了!以下是完整代码:

--------------------------------------------------------------------------------#include

#include



BOOL __cdecl sub_401000(LPCSTR lpName)

{

HANDLE v1; // eax@1

BOOL result; // eax@2

HANDLE hObject; // @1

struct _LUID Luid; // @3

struct _TOKEN_PRIVILEGES NewState; // @5



v1 = GetCurrentProcess();

if ( OpenProcessToken(v1, 0x28u, &hObject) )

{

    if ( LookupPrivilegeValueA(0, lpName, &Luid) )

    {

      NewState.Privileges.Luid.LowPart = Luid.LowPart;

      NewState.PrivilegeCount = 1;

      NewState.Privileges.Luid.HighPart = Luid.HighPart;

      NewState.Privileges.Attributes = 2;

      result = AdjustTokenPrivileges(hObject, 0, &NewState, 0x10u, 0, 0);

      if ( !result )

      {

      printf("adjust error\n");

      result = CloseHandle(hObject);

      }

    }

    else

    {

      printf("can't find privilege error\n");

      result = CloseHandle(hObject);

    }

}

else

{

    result = printf("open process error\n");

}

return result;

}





int __cdecl main(int argc, const char **argv, const char **envp)

{      

      HKEY hKey;

      LONG result;

      INTi=0;



      sub_401000("SeBackupPrivilege");//申请备份权力;

      DeleteFileA("C:\\Saved.hiv");

      if ( RegOpenKeyExA(          //打开注册表;

         HKEY_LOCAL_MACHINE,

         "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify",

         0,

         KEY_ALL_ACCESS,

         &hKey) )

{

    printf("can't get key handle\n");

    result = 0;

}

else

{

   if ( RegSaveKeyA(hKey, "C:\\Saved.hiv", 0) ) //备份注册表;

    {

      printf("Can't dump Service info\n");

      CloseHandle(hKey);

      result = 0;

    }

    else

    {

             printf("Saved!\n\n");

      CloseHandle(hKey);

      sub_401000("SeRestorePrivilege"); //申请恢复权力;

      if ( RegOpenKeyExA(

             HKEY_LOCAL_MACHINE,

             "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify",

             0,

             KEY_ALL_ACCESS,

             &hKey) )

      {

      printf("Can't open Service key\n");

      result = 0;

      }

      else

      {

            if ( RegRestoreKeyA(hKey, "infect.hiv", 8u) )//导入注册表;

      {

          while ( i<5 )

                  {

                        RegRestoreKeyA(hKey, "infect.hiv", 8u);

                        ++i;

                  }

      }      

      MessageBoxA(0, "请查看notifyDLL项,如果变更就是成功拉~点击确定恢复","哈哈",0);

      while ( i<10 )

                  {

                        RegRestoreKeyA(hKey, "C:\\Saved.hiv", 8u);

                        ++i;

                  }

      CloseHandle(hKey);

      result = 1;

      }

    }

}

      return 0;

}
复制代码--------------------------------------------------------------------------------

【经验总结】
--------------------------------------------------------------------------------
1.要细心观察每个CALL的作用,逆向程序与逆算法不同.程序对每个CALL调用的紧密相连要求很高,有一个

CALL缺少了整个程序就不能运了.

2.要逆向一个程序还要有相关程序语言的知识,如这个是C的你就不能连C有个主函数main都不知道那还逆

什么啊!还有此程序源码只能在Microsoft Visual C++ 6.0 中运行,若在别的编译器中就会错误了.那是因

为struct _LUID Luid;这句别的编译器中没有这样的定义所以编译不能通过要如何解决自己百一下就OK!

3.要勤动手,每个程序的都有不少的API而每API的作用都不一样参数更是让人头痛要不勤查想逆出个程序

那是不太可能的.IDA是很强大,但它不是神不是没有错误的像这个BOX函数也反错了,逆向=毅力+勤力!

--------------------------------------------------------------------------------

【版权声明】: 本文原创于UpK论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2010年03月21日 23:23:36

gameuser 发表于 2010-11-21 12:49:13

不错,学习一下。

sd051236 发表于 2011-1-23 02:25:57

学习下但是看不懂
页: [1]
查看完整版本: OD与IDA联合逆向还原C程序