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
不错,学习一下。 学习下但是看不懂
页:
[1]