【笔记】借助实例分析回顾汇编指令
本帖最后由 leo_zch 于 2017-11-16 15:27 编辑这个分析是看恶意代码分析实战时,为了回顾一些汇编指令以及熟悉分析流程而写的,发在了自己的博客,加深一下理解。现在注册了论坛,搬过来让大家看看有啥毛病,欢迎指正
1、字符串
根据Internet、Connection、OpenUrl等可以看出程序有url访问操作,访问的url可能就是http://www.practicalmalwareanalysis.com/cc.htm,还有一个Parsed command,可能涉及对参数的解析
2、打开汇编窗口,程序从_main开始,这里简单分析一下_main函数:
http://codefocus.top/wp-content/uploads/2017/09/122-300x179.png
首先,_main调用了sub_401000(),接下来拷贝了EAX中的值并与0进行比较,由此可以还原一个函数调用:var_4 = sub_401000()
然后,cmp和jnz指令发生条件跳转,cmp比较var_4和0,如果var_4==0,ZF置1,否则置0,从而决定jnz是否发生跳转。jnz当ZF为0时发生跳转,此时var_4!=0,写出伪代码如下:
if(var_4==0){
//不发生跳转
xor eax,eax
jmp short loc_40117B
}else{
jmp loc_401148
}
3、sub_401000()
_main首先调用了sub_401000(),并返回一个Int值
http://codefocus.top/wp-content/uploads/2017/09/123-300x231.png
在sub_401000()主程序中,InternetGetConnectedState函数被调用,由其名字不难猜出这是一个判断网络连接状态的函数,msdn上有其介绍如下:
BOOL InternetGetConnectedState(
_Out_ LPDWORD lpdwFlags,
_In_ DWORD dwReserved
);
两个参数:
lpdwFlags is a Pointer to a variable that receives the connection description,函数通过这个参数判断特定网络是否正常连接,例如LAN、MODEM等,但是没有0,猜测应该是只要有一个可以连接就返回TRUE。
dwReserved为保留字,必须为0
这里逻辑如下:如果存在网络连接,InternetGetConnectedState返回True,cmp将返回值与0比较使ZF置0,从而jz不会跳转。伪代码:
if(InternetGetConnectedState(0,0)){...}
else jmp loc_40102B
接下来无论跳转不跳转,sub_40117F(const char *format_str)都会被调用,参数为一个格式化字符串,根据前面的函数状态和这里字符串内容可以推知:sub_40117F()为printf函数
这两个分支打印了字符串后,进行了类似的操作:操作EAX,跳到loc_40103A退出函数.
第一个有网络连接时,EAX被置1,无连接跳转后通过xor eax,eax;EAX被置0
由调用约定,EAX一般存储被调函数的返回值
由此,完整伪代码如下:
if(InternetGetConnectedState(0,0)){
printf("Success,Internet connection\n");
return 1;
}else{
printf("Error,no connected\n");
return 0;
}
4:伪代码扩充
http://codefocus.top/wp-content/uploads/2017/09/124-300x300.png
int _main(){
int flag = sub_401000();
if(flag){
//jmp loc_401148;
var_8 = sub_401040();
//test eax,eax;相当于&操作,
if(var_8&var_8) reutrn 0;
//jmp loc_40115C;之前已经分析过sub_40117F为printf,可以在IDA中对sub_40117F进行重命名
printf("Success: Parsed command is %c\n",ecx_command);
Sleep(EA60h);
}
return 0;
}
5、sub_401040()
http://codefocus.top/wp-content/uploads/2017/09/125-300x234.png
在图中框出了几个函数调用和跳转,总结分析可知,该函数访问了szUrl,如果访问成功跳到loc_40109D,否则打印失败信息,关闭网络句柄。
1)InternetOpen:Returns a valid handle that the application passes to subsequent WinINet functions. If InternetOpen fails, it returns NULL. To retrieve a specific error message, call GetLastError.
即如果打开成功,它会返回一个有效的句柄。interHandler = InternetOpen(szAgent,0,0,0,0)
2)InternetOpenUrl:Returns a valid handle to the URL if the connection is successfully established, or NULL if the connection fails. To retrieve a specific error message, call GetLastError. To determine why access to the service was denied, callInternetGetLastResponseInfo.
通过1)获得的句柄请求url,获得一个URL的句柄。urlHandler=InternetOpenUrl(interHandler,szUrl,0,0,0,0)
3)cmp ,0;urlHandler与0比较,如果不为NULL,jmp loc_40109D
伪代码如下:
int sub_401040(){
interHandler = InternetOpen(szAgent,0,0,0,0);
urlHandler=InternetOpenUrl(interHandler,szUrl,0,0,0,0);
if(urlHandler){
jmp loc_40109D;
}
printf(aError2_1FailTo);
urlHandler.close();
return 0;
}
6、loc_40109D
http://codefocus.top/wp-content/uploads/2017/09/126-300x184.png
当urlHandler不为NULL时,首先调用了
1)var_4 = InternetReadFile(hFile,*lpBuffer,256,*lpdwNumberOfBytesRead)
注: hFile :Handle returned from a previous call to InternetOpenUrl.
lpBuffer :Pointer to a buffer that receives the data.
dwNumberOfBytesToRead :Number of bytes to be read.
lpdwNumberOfBytesRead :Pointer to a variable that receives the number of bytes read. InternetReadFile sets this value to zero before doing any work or error checking.
即从hFile中读取512字节的数据存到lpBuffer中,成功返回True,否则返回False
2)接下来判断是否读取成功,成功则跳转到loc_4010E5继续执行,否则打印错误信息,关闭句柄,退出
if(var_4) jmp loc_4010E5;
else{
printf(aError2_2FailTo);
interHandler.close();
return 0;
}
3)loc_4010E5:在这里,程序将buffer与'<‘比较,var_20F与‘!’比较。。。但是Buffer我们已经知道Buffer是一个连续的512字节的数组,所以这里应该是将Buffer的前四字节与'<!–‘比较,如果前面比较成功,则将第五字节存入al,然后返回退出。
http://codefocus.top/wp-content/uploads/2017/09/127-300x135.png
我们需要修改此处的栈,将Buffer定义为一个512字节的数组,在loc_4010E5处按Ctrl-K,然后右键Buffer第一个字节,将Buffer定义为一个512字节的数组
http://codefocus.top/wp-content/uploads/2017/09/129-2-300x125.png
7、如此,sub_401040()的完整伪代码就可以写出来了,如下
int sub_401040(){
interHandler = InternetOpen(szAgent,0,0,0,0);
urlHandler=InternetOpenUrl(interHandler,szUrl,0,0,0,0);
if(urlHandler){
//jmp loc_40109D;
var_4 = InternetReadFile(hFile,*lpBuffer,256,*lpdwNumberOfBytesRead);
if(var_4) {
//jmp loc_4010E5;
if(buffer=='<'){
if(buffer=='!'){
if(buffer=='-'){
if(buffer=='-') return buffer;
}
}
}
}
}
printf(aError2_1FailTo);
urlHandler.close();
return 0;
}
8、回顾_main函数主体,首先判断电脑是否有网络连接,然后访问http://www.practicalmalware.com/cc.htm并解析命令,var_8用来存储命令字符,然后判断var_8是不是空,如果不是,打印解析成功的命令,然后Sleep()
int _main(){
int flag = sub_401000();
if(flag){
//jmp loc_401148;
var_8 = sub_401040();
//test eax,eax;相当于&操作,
if(var_8&var_8) reutrn 0;
//jmp loc_40115C;之前已经分析过sub_40117F为printf,可以在IDA中对sub_40117F进行重命名
printf("Success: Parsed command is %c\n",ecx_command);
Sleep(EA60h);
}
return 0;
}
9、当然这些可以通过IDA的F5直接看出,在这里主要是为了巩固一些知识,并且逆向中一般并不会很容易的就能F5出正确的结果。 大佬大佬,先给大佬留个好印象,顺便留个脚印以后看
页:
[1]