首页
社区
课程
招聘
[原创] 默默无闻·恶意代码分析Lab5
发表于: 2021-4-5 06:44 6486

[原创] 默默无闻·恶意代码分析Lab5

2021-4-5 06:44
6486

[原创]默默无闻·恶意代码分析Lab1

参照书籍:《恶意代码分析实战》;

文件来源:官网随书文件、或者附件中(文件密码:apebro);;

使用工具:WinHex、CFF、StudyPE+、Exeinfo PE、Resource Hacker、Depends Walker、OD、IDA、MSDN;

只用IDA Pro分析在文件Lab05-01.dll中发现的恶意代码。这个实验的目标是给你的一个用IDA Pro动手的经验。如果你已经用IDA Pro工作过,你可以选择忽略这些问题,而将精力集中在逆向工程恶意代码上。

image-20210404235334914

很显然,没有壳;

再审题,基本上都是IDA Pro的操作,看来是一次复习IDA Pro使用了。

1、DLLMain的地址是什么?

image-20210404235828438

image-20210405000039790

获得DLLMain的位置0x1000D02E;

这里有一个知识点:就是这里的地址是理论上的VA,注意是理论上的,因为如果理论位置被加载了,就需要让系统重新选择一个位置,然后重定位。所以有效的地址应该是换算成RVA

2、使用Imports窗口并浏览到gethostbyname,导入函数定位到什么地址?

image-20210405000944550

获得定位0x100163CC;

3、有多少函数调用了gethostbyname

image-20210405001431726

image-20210405002313071

共18次引用,Type处p代表被调用,r代表[…]“读取”式引用,所以有9个交叉引用对gethostbyname()进行调用;

4、将精力集中在位于0x10001757处的对gethostbyname的调用,你能找出哪个DNS请求将被触发吗?

image-20210405003439929

这里是一个call操作,所以向上找参数;

所以先要找到数据地址头;

image-20210405005742483

将鼠标放在黄色字符串上,就能看到完整字符串;或者打开Strings窗口,检索红色框起来的字符串;

image-20210405005925461

这就找到了网址,所以会对该网址发起DNS请求,获得其IP地址;

5、IDA Pro识别了在0x10001656处的子过程中的多少个局部变量?

image-20210405011521090

这个就很显然了,偏移为负的是局部变量

IDA很智能的识别出了23个局部变量;

6、IDA Pro识别了在0x10001656处的子过程中的多少个参数?

image-20210405011611041

偏移为正的是参数

IDA很智能的识别出了1个参数;

7、使用Strings窗口,来在反汇编中定位字符串\cmd.exe /c。它位于哪?

image-20210405012018575

找到字符串地址0x10095B34;

8、在引用cmd.exe /c的代码所在的区域发生了什么?

image-20210405012327733

双击Address地址,跳转到IDA View-A代码;

image-20210405012632751

这是个push操作;

9、在同样的区域,在0x100101c8处,看起来好像dword_1008E5C4是一个全局变量,它帮助决定走哪条路径。那恶意代码是如何设置dword_1008E5C4的呢?(提示:使用dword_1008E5C4的交叉引用。)

image-20210405014455621

image-20210405014710391

image-20210405015226786

image-20210405020752653

得到:

由代码可知:dwPlatformId与数字2进行比较,如果相等,al置1,也就是返回true

由此可以简单的判断当前操作系统的版本;

只需要查到GetVersionExA()函数的参数类型,然后一直向上找定义,就能找到结构体类型;

10、在位于0x1000FF58处的子过程中的几百行指令中,一系列使用memcmp来比较字符串的比较。如果对robotwork的字符串比较是成功的(当memcmp返回0),会发生什么?

image-20210405024950679

image-20210405035201538

终于找到了,用Graph View看更壮观,真的好多memcmp

image-20210405035937249

指令是个push,大概率是一个传参操作,继续向下找call

注意看call下面那句,明显是平栈操作,很显然memcmp使用的是__cdecl 调用方式;

根据题意,memcmp返回0

再复习一下test指令;

所以test eax,eax等于and eax , eax也就是and 0 , 0,结果为0,ZF位置1

如果ZF位为1jnz指令则不跳转;

image-20210405043341855

image-20210405051018253

说明它查询了路径为HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WorkTimeWorkTimes的注册表项;

有意思的是看sub_100038EE处的函数;

image-20210405051611968

这是一个隐藏的Socket函数,所以应该是先查询注册表值,然后再发送一个网络信息;

11、PSLIST导出函数做了什么?

image-20210405052019165

image-20210405052154539

最近的跳转是关联sub_100036C3函数的返回值;

image-20210405052339901

这函数很眼熟,是获取操作系统版本的;

至于25是操作系统版本号;

答案给出的是Windows Vista/7或是Windows XP/2003/2000;

image-20210405061917138

image-20210405053146610

image-20210405062057623

image-20210405053644298

image-20210405062354634

依旧是到了sub_100038BB;

image-20210405053551125

综上所述,这两条代码路径都使用CreateToolHelp32Snapshot函数,从字符串和API来看,是获取进程列表,通过send将进程列表通过socket发送出去;

12、使用图模式来绘制处对sub_10004E79的交叉引用图。当进入这个函数时,哪个API函数可能被调用?仅仅基于这些API函数,你会如何重命名这个函数?

image-20210405063330860

13、DLLMain直接调用了多少个Windows API?多少个在深度为2时被调用?

先通过g键跳到0x1000D02E的DLLMain处;

右击进入Graph View视图;

image-20210405064038052

将红标处设置为2

image-20210405064258528

14、在0x10001358处,有一个对Sleep(一个使用一个包含要睡眠的毫秒数的参数的API函数)的调用。顺着代码向后看,如果这段代码执行,这个程序会睡眠多久?

先通过g键跳到0x10001358处;

找到Sleep函数;

image-20210405064507452

15、在0x10001701处是一个对socket的调用。它的3个参数是什么?

16、使用MSDN页面的socket和IDA Pro中的命名符号常量,你能使参数更加有意义吗?在你应用了修改以后,参数是什么?

image-20210405070724604

选中数字,右击选择Use Symbolic Constant,出现对话框选择OK就好了;

image-20210405071009941

这就成功了;

17、搜索in指令(opcode 0xED)的使用。这个指令和一个魔术字符串VMXh用来进行VMware检测。这在这个恶意代码中被使用了吗?使用对执行in指令函数的交叉引用,能发现进一步检测VMware的证据吗?

有两种方式:

选择Find All Occurrences,可以列出所有匹配;

image-20210405072059097

选中0x564D5868hr键可以看出字符串等于VMXh

image-20210405072826713

看书后答案,这里涉及了反虚拟机技巧,17章的时候会有更详细的介绍;

18、将你的光标跳转到0x1001D988处,你发现了什么?

先通过g键跳到0x1001D988处;

猜测是一端硬编码;

19、如果你安装了IDA Python插件(包括IDA Pro的商业版本的插件),运行Lab05-01.py,一个本书中随恶意代码提供的PDA Pro Python脚本,(确定光标是在0x1001D988处。)在你运行这个脚本后发生了什么?

根据题意,选择菜单File -> Script File,选择随书文件中的Python脚本运行;

可惜我的版本并不支持python脚本,掠过掠过;

20、将光标放在同一位置,你如何将这个数据转成一个单一的ASCII字符串?

21、使用一个文本编辑器打开这个脚本。它是如何工作的?

看似东西不多,做起来也快,就是写笔记写帖子总是很慢很慢;

坚持吧,坚持总会有结果的;

共勉!

 
 
 
 
 
 
 
mov eax , off_10019040    ;这里是一个数据地址头
add eax , ODh            ;ODh大小
push eax                ;把eax压栈
mov eax , off_10019040    ;这里是一个数据地址头
add eax , ODh            ;ODh大小
push eax                ;把eax压栈
 
 
 
 
 
 
 
 
 
 
 
// GetVersionEx函数获取当前运行的操作系统版本的扩展信息。
BOOL GetVersionEx(
  LPOSVERSIONINFO lpVersionInformation   // pointer to version
                                         // information structure
);
// GetVersionEx函数获取当前运行的操作系统版本的扩展信息。
BOOL GetVersionEx(
  LPOSVERSIONINFO lpVersionInformation   // pointer to version
                                         // information structure
);
 
bool sub_10003695(){
    typedef struct {    // 通过MSDN类型溯源获得结构体完整类型;
        DWORD dwOSVersionInfoSize;
        DWORD dwMajorVersion;        // 函数没使用
        DWORD dwMinorVersion;        // 函数没使用
        DWORD dwBuildNumber;        // 函数没使用
        DWORD dwPlatformId;
        CHAR   szCSDVersion[ 128 ];   // Maintenance string for PSS usage
    }VersionInformation;
 
    VersionInformation.dwOSVersionInfoSize = 0x94h;
    GetVersionExA(&VersionInformation);
 
    return VersionInformation.dwPlatformId == 2;
}
bool sub_10003695(){
    typedef struct {    // 通过MSDN类型溯源获得结构体完整类型;
        DWORD dwOSVersionInfoSize;
        DWORD dwMajorVersion;        // 函数没使用
        DWORD dwMinorVersion;        // 函数没使用
        DWORD dwBuildNumber;        // 函数没使用
        DWORD dwPlatformId;
        CHAR   szCSDVersion[ 128 ];   // Maintenance string for PSS usage
    }VersionInformation;
 
    VersionInformation.dwOSVersionInfoSize = 0x94h;
    GetVersionExA(&VersionInformation);
 
    return VersionInformation.dwPlatformId == 2;
}
 
 
 
 
 
// 比较两个缓冲区中的字符。
 
int memcmp( const void *buf1, const void *buf2, size_t count );
 
// Return Value
 
// 返回值指示缓冲区之间的关系。
// 返回buf1和buf2的第一个计数字节的值关系
//  < 0 buf1 小于 buf2
//  = 0 buf1 等于 buf2
//  > 0 buf1 大于 buf2
// 比较两个缓冲区中的字符。
 
int memcmp( const void *buf1, const void *buf2, size_t count );
 
// Return Value
 
// 返回值指示缓冲区之间的关系。
// 返回buf1和buf2的第一个计数字节的值关系
//  < 0 buf1 小于 buf2
//  = 0 buf1 等于 buf2
//  > 0 buf1 大于 buf2
// RegOpenKeyEx函数打开指定的注册表键。
 
LONG RegOpenKeyEx(
  HKEY hKey,         // handle to open key
  LPCTSTR lpSubKey,  // address of name of subkey to open
  DWORD ulOptions,   // reserved
  REGSAM samDesired, // security access mask
  PHKEY phkResult    // address of handle to open key
);
// 返回值
// 如果函数成功执行,返回值为ERROR_SUCCESS。
// 如果函数失败,返回值为WINERROR.H中定义的非零错误代码。您可以使用带有 FORMAT_MESSAGE_FROM_SYSTEM标志的FormatMessage函数来获取错误的通用描述。
// RegOpenKeyEx函数打开指定的注册表键。
 
LONG RegOpenKeyEx(
  HKEY hKey,         // handle to open key

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2021-4-8 14:55 被平头猿小哥编辑 ,原因: 上传附件
上传的附件:
收藏
免费 5
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//