恶意代码分析实战 Lab 9-3 习题笔记

版权声明:本文为博主辛辛苦苦码字原创文章,转载记得表明出处哦~ https://blog.csdn.net/isinstance/article/details/79034258

Lab 9-3

问题

1.Lab09-03.exe导入了哪些DLL?

解答: 我们还是跟着书上的步骤开始,先看看Lab09-03.exe导入了哪些DLL

图片

这里我们可以看出,导入了KERNEL32.DLLNETAPT32.DLLDLL1.DLLLDLL2.dll这四个DLL ,然后我们去IDA里面看看

我们跟随书中做法,找到LoadLibrary调用并检查

图片

反正我是找不到哪里查看LoadLibrary的两个交叉引用

图片

第一个调用call是这里

图片

这里的入参是DLL3.dll,这里从DLL3.dll导入函数

然后第二个调用在这里

图片

这里的入参是user32.dll

第三个call和第一个一样

第四个call和第二个一样

然后这就是书中所谓的交叉引用,这些DLL在程序执行过程中可能被动态的加载

所以这个题的答案如上所述那四个DLL


2.DLL1.dll、DLL2.dll、DLL3.dll要求的基地址是多少?

解答: 我们按照书中的方法做一遍看看

我们用打开PEview来查看这个DLL请求的基准地址(程序的基准地址是值加载这个DLL的时候去哪里找他的那个地址)

按照书上的说法是这样看

图片

然后请求的基准地址是0x100000000,也就是Data那里的值

然后我们再打开DLL2.dll

图片

这里的请求的地址也是0x10000000的基准地址

图片

DLL3.dll也是0x10000000


3.当使用OllyDbg调试Lab09-03.exe时,为DLL1.dll、DLL2.dll、DLL3.dll分配的基地址是什么?

解答: 还是根据书上的办法我们走一遍

根据我们第一问的分析,DLL3.dll是动态加载的,只有DLL1.dllDLL2.dll是一开始就被导入的

图片

所以DLL1.dllDLL2.dll会被马上加载

这里要动态调试,用的是OllyDbg

我们先在第一个调用LoadLibrary的地址加一个断点,也就是这里

图片

第一个call的调用是这里0x401041

图片

我们在OD里面找到这里加上断电

图片

我们在这里设置断点,然后运行

然后运行暂停之后打开View->Memory这个地方,来查看此时的内存地址

图片

这是我的显示,我们在这里面找,会找到一个叫DLL1的导入

图片

我们可以看到,在这里,我们的DLL1获得了它期望的基准地址,为0x10000000(7个0)

然后我们找DLL2

图片

然后我们可以看到DLL2获得的基准地址是0x3d0000(各个机器上的可能不同,如作者机器上就是0x320000

然后我们继续找DLL3

这里没找到,我们执行下一步LoadLibrary这个函数

刚刚我们断点是在LoadLibrary这里就停住了,所以没有DLL3.dll的动态导入

然后我们单步执行之后就会发现内存中已经导入了DLL3.dll

图片

这里我们放大一点看看

图片

这里的DLL3的基准地址就是0x580000

所以这题的答案就是上面这些,答案不同机器可能不同,但是方法知道就行了


4.当Lab09-03.exe调用DLL1.dll中的一个导入函数时,这个导入函数都做了什么?

解答: 我们开始找这个DLL1的导入函数

IDA来分析这个代码

图片

可以看出在IDA中下显示的是三个函数,其中有一个是从DLL1.dll中导入的

其他两个都DLL2.dll导入的函数

图片

这里的地址是0x405000

然后我们就开始用IDA来反汇编DLL1.dll

图片

这里并没有找到这个printf类似的输出函数

然后我们看看这个dword_10008030是个什么

图片

我们可以看到这个有个字符串

"DLL 1 mystery data %d"

这个应该某个printf系列的函数要调用的,因为我们看到%d这个东西

然后我们研究一个这个dword_10008030的交叉引用

我们可以看到这个的引用

图

第一个就是我们刚刚的DLLMain函数

下一个就是在DLL1Print导出函数里面的

图

DLL1Print函数的大概像这样

在调用sub_10001038函数之前,压栈了两个参数,一个是eax,其实就是dword_10008030,还有一个aDll1MysteryDat,其实这两个值一开始是指向一个地址的相同值,但是后来不是经过DLLMain函数的一顿操作之后

图片

eaxGetCurrentProcessId的返回值,所以这时候经过MOV操作之后,dword_10008030已经成为了这个返回值的

所以这时候入参一个是pid,一个是那个字符串

图片

所以这里我们可以猜测这个sub_10001038其实就是某个printf系列函数,用于格式化输出

然后我们可以进去这个函数看看到底是什么样的

图片

这里又调用了sub_10001439,调用之前我们可以看到这个函数的入参有一个FILE*类型的指针,所以这个函数很有可能是fprintf,用于将一个字符串输出到一个文件

然后我们打开DLL2.dll

图片

我们可以发现这个DLL2的大概结构是这样,有两个导出函数,一个是DLL2ReturnJ,然后一个是DLL2Print

我们看看DLL2Print这个导出函数

图片

这里有个字符串DLL 2 mystery data %d\n,之前有一个全局变量dword_1000B078

我们查查这个全局变量的引用

图片

这里有三个引用,其中一个在DLLMain里面,一个在DLL2Print里面,一个在DLL2Return里面

图片

DLLMain里面,这个全局变量存储的是CreateFileA之后返回的句柄,打开的文件名是temp.txt

图

DLL2ReturnJ导出函数中,这里将eax的值用这个全局变量复制之后,然后返回给调用者

所以这里的DLL2Print

图

这里的sub_1000105Aprintf系列函数中的一个

所以DLL2Print的作用就是输出temp.txt的句柄,然后这个句柄被DLL2ReturnJ返回

然后我们回到Lab09-03.exe里面

图

我们看到这里调用完DLL2ReturnJ之后 ,就把返回值eax赋值给了hFile,也就是书上的hObject这个东西

然后又传递给了WriteFile之后,那个恶意网址的内容就被写入了文件中,也就是temp.txt里面

然后我们继续看下一个调用

图

然后下一个调用是很正常的关闭句柄,我们继续往下

图

然后这个调用是LoadLibraryA载入DLL3.dll

图

图

然后下一个调用GetProcAddress动态解析DLL3PrintDLL3GetStructure

我们似乎还没有分析过DLL3.dll,现在我们开始用IDA开始打开看看

图片

DLL3.dll打开之后就是这样的

我们可以先看看DLLMain函数的样子

图

这里第一个调用是MultiByteToWideChar这个东西

MSDN里面,这个MultiByteToWideChar是这样定义的

Maps a character string to a UTF-16 (wide character) string. The character string is not necessarily from a multibyte character set.
将字符串映射到UTF-16(宽字符)字符串。字符串不一定来自多字节字符集

这是一个对字符串进行操作的函数

而这个字符串是这样的

图

ping www.malwareanalysisbook.com

这看着像一个命令的样子

然后我们出来,看看其他的导出函数是什么样的

点击小+号就可以出来了一个

图

这是DLL3Print这个函数

图

可以看出这个函数有个字符串

DLL 3 mystery data %d\n

那个没标注的函数sub_1001087就是一个类printf的函数

然后我们点击第三个小+号就出来DLL3GetStructure这个导出函数了

图

图

这里是将dword_1000B0A0赋值给了eax指向的地址

然后返回eax

然后回到Lab09-03.exe里面,继续分析

图

然后这里先调用了NetScheduleJobAdd,光看名字貌似是个网路任务添加的函数,我们看看MSDN里面的解释

The NetScheduleJobAdd function submits a job to run at a specified future time and date. This function requires that the schedule service be started on the computer to which the job is submitted.
NetScheduleJobAdd函数提交一个作业在指定的未来时间和日期运行。此功能要求在提交作业的计算机上启动计划服务。

没错的,这个函数会当时开启一个服务

然后这个函数的入参解释是这样的

NET_API_STATUS NetScheduleJobAdd(
  _In_opt_ LPCWSTR Servername,
  _In_     LPBYTE  Buffer,
  _Out_    LPDWORD JobId
);

根据IDA里面的显示和对照MSDN,我们可以分析得出一下结论

NET_API_STATUS NetScheduleJobAdd(
  _In_opt_ LPCWSTR Servername = 0,
  _In_     LPBYTE  Buffer = [ebp + Buffer],
  _Out_    LPDWORD JobId = [ebp + JobId]
);

然后设置完NetScheduleJobAdd之后

开始调用Sleep函数休眠2710h

书上说,这个BufferDLL3.dll中的导出函数DLL3GetStructure的返回值

我们来分析一下

图

调用完GetProcAddress之后,返回值被保存在eax里面,然后被保存到了[ebp+var_10]里面

然后通过lea[ebp+Buffer]的值的地址保存到了edx

然后在把这个edx压栈之后,开始调用[ebp+var_10]也就是eax也就是DLL3GetStructure这个导出函数

图

因为我们知道这个[ebp+Buffer]_In_ LPBYTE结构,书上是说是AT_INFO,但是我们查MSDN显示的已经不是这个结构了

图

所以在DLL3GetStructure导出函数里面我们可以清晰的看到,入参是[ebp+arg_0]也就是[ebp+Buffer]

然后经过一个mov指令,将dword_1000B0A0赋值给了[ebp+Buffer]

所以这个dword_100B0A0的结构应该就是Buffer的结构也就是_In_ LPBYTE(书上是AT_INFO

然后我们这个为什么分析完了之后,我们按照书上的做一下

我们再用IDA打开DLL3.dll,然后找到导出函数DLL3GetStructure

在结构体窗口按INSERT键添加标准的结构体AT_INFO(书上是这么说)

结构体窗口在这里

图片

然后我们按INSERT

图

我们先试试这个AT_INFO存不存在

我们这里点Add standard structure

图

然后我们查找这个结构体

图

这个结构体是存在的

我们查查_In_ LPBYTE这个结构体

并不存在

图

然后我们再去查看MSDN,发现下面有这么一句话

图

ok,的确是AT_INFO,然后添加这个结构

然后我们来到导出函数界面

双击这个结构体之后出现这些

图

找到这个东西Struct var

图

选择结构体

图

然后来到DLLMain这里

我们就会发现这里的显示更加明白了

图

对比一下以前的DLLMain

图

然后我们就知道这个DLL3GetStructure大概是干什么的了

这里初始化了一个AT_INFO的结构之后,返回给Lab09-03.exe

我们看一下具体的AT_INFO的结构定义

typedef struct _AT_INFO {
  DWORD_PTR JobTime;
  DWORD     DaysOfMonth;
  UCHAR     DaysOfWeek;
  UCHAR     Flags;
  LPWSTR    Command;
} AT_INFO, *PAT_INFO, *LPAT_INFO;

根据IDA里面的显示,我们可以完成如下的结构赋值

typedef struct _AT_INFO {
  DWORD_PTR JobTime = 36EE80h;
  DWORD     DaysOfMonth = 0;
  UCHAR     DaysOfWeek = 7Fh;
  UCHAR     Flags = 11h;
  LPWSTR    Command = "ping www.malwareanalysisbook.com";
} AT_INFO, *PAT_INFO, *LPAT_INFO;

这里比较容易理解的就是Command元素了,其他的我们一个一个对对看

JobTime
Type: DWORD_PTR

A pointer to a value that indicates the time of day at which the job is scheduled to run. The time is the local time at a computer on which the schedule service is running; it is measured from midnight, and is expressed in milliseconds.

指向指示作业计划运行的时间的值的指针。时间是运行日程安排服务的计算机的本地时间;它是从午夜开始测量的,用毫秒表示。

JobTime = 36EE80h翻译过来就是3600000d‬毫秒,3600d秒,然后60分钟,最后就是一个小时

也就是从午夜后的一个小时开始运行这个东西

然后下一个

DaysOfMonth
Type: DWORD

A set of bit flags representing the days of the month. For each bit that is set, the scheduled job will run at the time specified by the JobTime member, on the corresponding day of the month. Bit 0 corresponds to the first day of the month, and so on.

The value of the bitmask is zero if the job was scheduled to run only once, at the first occurrence specified by the JobTime member.

代表月份日期的一组比特标志。对于设置的每个位,计划的作业将在JobTime成员指定的时间运行,在该月的相应日期。位0对应于月份的第一天,依此类推。

如果在JobTime成员指定的第一个事件中计划只运行一次,则位掩码的值为零。

根据上面的解释,DaysOfMonth = 0代表的意思就是在每个月的第一天运行

然后

DaysOfWeek
Type: UCHAR

A set of bit flags representing the days of the week. For each bit that is set, the scheduled job will run at the time specified by the JobTime member, on the corresponding day of the week. Bit 0 corresponds to Monday, and so on.

The value of the bitmask is zero if the job was scheduled to run only once, at the first occurrence specified by the JobTime member.

代表星期几的一组比特标志。对于设置的每个位,计划的作业将在JobTime成员指定的时间在相应的星期几运行。位0对应于星期一,以此类推。

如果在JobTime成员指定的第一个事件中计划只运行一次,则位掩码的值为零。

那这个DaysOfWeek = 7Fh,其实就是127d,这个值明显大于0x6h也就是星期天,书上说的每个星期任意一天的1:00运行Command

然后我们看Flag

A set of bit flags describing job properties.

When you submit a job using a call to the NetScheduleJobAdd function, you can specify one of the following values.

描述作业属性的一组位标志。

当您使用对NetScheduleJobAdd函数的调用提交作业时,可以指定下列其中一个值。

Flags = 11h,我们用替换看看这个值是代表哪个值

图片

这个值在替换之后就是这个JOB_NOTIFY_FIELD_START_TIME,这个值在MSDN里面找不到

忽略它,然后书上说,这个结构的意思就是在一周中的任意一天1:00AM执行ping malwareanalysisbook.com这个命令


5.当Lab09-03.exe调用WriteFile函数的时候,它写入的文件名是什么?

解答: 这个我们一点一点的继续分析

我们先找到这个WriteFile的位置

图片

这里我们上面已经分析过了,是写入从DLL2ReturnJ打开返回的temp.txt


6.当 Lab09-03.exe使用NetScheduleJobAdd创建一个job时,从哪里获取第二个参数的数据?

解答: 如下图

图片

NetScheduleJobAdd这个函数的第二个参数就是ecx别名Buffer,这个Buffer我们上面说过是怎么传入这个参数,从DLL3GetStructure里面初始化之后的缓冲区


7.在运行或调试Lab09-03.exe时,你会看到Lab09-03.exe打印出三块神秘数据。DLL 1的神秘数据,DLL 2的神秘数据,DLL 3的神秘数据分别是什么?

解答: 在DLL1中打印出来的是当前进程的PID,在DLL2中打印出来的是temp.txt文件的句柄,在DLL3中打印出来的是ping malwareanalysisbook.com在内存中的地址


8.如何将DLL2.dll加载到IDA Pro中,使得它与OllyDbg使用的加载地址匹配?

解答: 书上的说法是这样的

当使用IDA PRO加载DLL时选择手动加载,当提示时,输入新的映像基准地址。

图片

这里选择这个Manual load

然后编辑地址

图

输入你想加载的地址就行了

本文完

猜你喜欢

转载自blog.csdn.net/isinstance/article/details/79034258
今日推荐