目录
笔记:
Windows API:管理恶意代码与微软程序库之间的交互方式
常用API类型:
类型 | 前缀 | 描述 |
WORD | w | 一个16位的无符号数值 |
DWORD | dw | 一个双字节,32位的无符号数值 |
Handles | H | 一个对象索引 HModule HKey |
Long Pointer | L | Unidentified |
Callback | 表示一个会被API调用的函数 InternetSetStatusCallback |
文件系统函数:
CreateFile:参数dwCreationDisposition控制这个函数是否创建一个新文件
ReadFile/WriteFile:
CreateFileMapping和MapViewOfFile:第一个函数从磁盘中加载一个文件到内存中。第二个函数返回一个指向映射的基地址指针,用来访问内存中的文件。
特殊文件:
共享文件:
通过名字空间访问的文件:\\.\-直接访问物理设备
\Device\PhysicalMemory-直接访问内存,修改内核,隐藏用户空间的程序
备用数据流(ADS):允许附加数据添加一个已存在的NTFS文件中,相当于添加一个文件到另一个文件中。列目录时不会显现出。
Windows注册表:
用户特定设置
保存定义的类型信息
本地机器全局设置
定义默认用户,新用户,当前用户的配置
保存于当前硬件配置的设置(特别是当前与标准配置之间的不同部分)
RegOpenKeyEx:打开一个注册表进行编辑和查询
RegSetValueEx:添加一个新值到注册表,并设置它的数值
RegGetValue:返回注册表中一个值项的数值
.reg文件可以修改注册表
网络的服务器和客户端:
w2_32.dll:socket,bind,listen,accept
WSAStartup:这个函数在其他网络函数之前调用,以便为网络库分配资源。
WinINet:实现应用层协议wininet.dll
InternetOpen:初始化一个网络连接
InternetOpenUrl:用来访问一个URL
InternetReadFile:从互联网的下载文件中读取数据
DLL的使用方式:
保存恶意代码,将自身附加到一另一个进程中。
进程:
为每个进程提供一个内存起始地址,即使另一个程序的内存地址和其一样,也不会发生冲突,保存数据的物理地址不同。
恶意代码可以有自己的进程,也可以将自身代码作为其他进程的一部分进行执行
Createprocess 可以创建一个远程shell
线程:线程是Windows系统真正要执行的内容,CreateThread创建一个线程。lpStartAddress值是线程启动时代码运行的位置
1.使用此函数加载一个恶意的库文件,调用CreateThread时将起始地址设置为LoadLibrary的地址。
2.可以创建一个输入,一个输出线程
互斥量:用于协调多个线程和进程
WaitForSingleObject:获取对互斥量的访问
ReleaseMutex:使用完后,用这个函数释放
CreateMutex:创建互斥量
OpenMutex:调用获取另一个进程中的互斥量
服务:恶意代码执行附加码的另一种方式是作为服务安装(特权用户运行,不会在进程中显示)
OpenSCManager:返回一个服务控制管理器的句柄
CreateService:添加一个新服务到服务控制管理器。
StartService:启动一个服务,仅在服务被设置成手动启动时使用
服务类型:
WIN32_SHARE_PROCESS:将服务的代码保存在一个DLL中,在一个共享的进程中组合多个不同服务。
WIN32_OWN_PROCESS:在一个.exe文件中保存代码,作为一个独立的进程运行
KERNEL_DRIVER:加载代码到内核中运行
SC工具
组件对象模型(COM):被实现成为客户-服务器的框架。客户端是那些使用COM对象的程序,服务器是COM组件本身。
在调用COM线程之前,至少调用一次OleInitialize或CoInitializeEx函数
有两类标识符:类型标识符(CLSID) 接口标识符(IID)
1.CoCreateInstance函数获取对COM功能的访问,接收CLSID,IID
2.返回一个函数指针,这个指针保存在CoCreateInstance函数返回的结构体中。
如果恶意代码伪造成一个COM服务器,必然会导出以下函数,包括DllCanUnloadNow,DllGetClassObject,DllInstall,DllRegisterServer,DllUnregisterServer。
原生API:用来与Windows进行交互的底层API
NtReadFile
NtWriteFile
NtQueryInformation
NtContinue:异常处理执行后回到一个程序的主线程,但返回的位置可以在上下文指定。
也有Zw前缀的ZwReadFile
会在PE头的子系统指明是不是原生应用程序
实验:
Lab 7-1
1.使用IDApro查看导入函数
1
可能会创建一个服务,保证它会在系统重启运行
连接到一个URL,进行内容下载
SystemTimeToFileTime:
系统时间转换成UTC
时间
SetWaitableTimer:
设置一个定时的函数,在指定时间激活一个线程
Sleep:函数休眠
TerminaterProcess:
终止一个进程的运行
2.分析反汇编代码
lpServiceName->这个代表了要在此服务过程中运行的服务的名称->MalService
lpServiceProc->这个代表了指向ServiceMain函数的指针->sub_401040
StartServiceCtrlDispatcherA函数指定了服务控制管理器会调用sub_401040处
获取一个HGL345的互斥量,如果得到,就正常退出。
如果没有HGL345这个互斥量就添加一个,从而保证同一时间内,只有一个实例在运行。
调用OpenSCManager:打开一个服务控制管理器,来添加或者修改服务
GetModuleFileName:返回值是现在程序的或正在使用的DLL的全路径名,因为第一个参数hModule的值为0,所以这个函数是返回了这个可执行文件的全路径名
CreateService创建一个新的服务
lpBinaryPathName->是指这个可执行文件的位置,是由GetModuleFileName来获得
dwStartType->传入的值是2->对应Service_AUTO_START->指明这个服务在系统启动时自动运行
dwServiceType->传入值10->对应Service_Win32_OWN_Process->在自己的进程中运行一个服务
操作的一个SYSTEMIME结构体 ,一个通过年,月。。来指示时间的结构体。
year->0x834->2100,其他值置位0.
使用SetWaitableTimer的lpDueTimer参数设置等待的时间点
WaitForSingleObject进入等待,直到2100年1月1日
如果时间没有到的话,跳转到最下面,执行sleep函数休眠
如果时间到了,调用CreateThread 20次,这个值保存在esi。其中我们要重点关注的CreateThread的参数StartAddress,指明了哪个函数被当做这个线程的起始地址使用。双击StartAddress
最后是一个无条件跳转jmp,意味着会一直访问恶意网站下载网页内容。
3.结论
这个程序在2100年1月1日运行,并在一个机子上重启时自动运行,只允许存在一个实例。通过20线程不停访问恶意网站下载网站内容,造成DDos攻击。
Lab 7-2
这些函数都是与COM相关的
第一步初始化COM
CoCreateInstance获得一个COM对象,返回值标记为ppv
想要知道这个COM的功能,要找到接口IID和类型CLSID
在注册表中查找CLSID,互联网搜索IID
IID->IWebBrowser2
CLSID->Internet Explorer
程序调用了iexplore.exe导航到恶意网站
Lab 7-3
初级静态分析:
.exe的字符串 kerne132.dll和kernel32.dll的不同。
.exe的导入函数 CreateFileA,CreateFileMappingA,MapViewOfFile打开一个文件并把它映射到内存中。
FindFirstFileA,FindNextFileA搜索目录
在导入函数中并没有LoadLibrary或GetprocAddress并没有调用附属的.dll
.dll的字符串 可能会连接到这个IP exec可能是个后门程序
.dll的导入函数 这个.dll只有导入函数,并没有导出函数。这不符合一个.dll的特点。
休眠函数slepp
创建进程函数CreateprocessA
有关于互斥量的函数CreateMutexA和OpenMutexA
网络信息交互函数WSAStartup(分配网络资源),socket,send等等
代码静态分析
.dll反汇编代码
对于代码多的情况,可以直接在IDApro中查看call function序列来简要分析过程。这个程序首先调用_alloca_probe来分配栈空间。然后调用互斥量函数来确保一个时期只有一个实例在运行。连接一个ip地址进行发送消息和接收消息。最后休眠结束。所以我们重点关注关于网络的函数。
连接到服务器发送hello字节后,等待服务器传过来的字节。用recv接收,如果前5个字节是sleep,则进入休眠。如果前四个字节是exec。跳转到loc_100011B6.
调用createProcess,这里关注参数lpCommandline
buf中放的接收的数据, 而CommandLine的位置是buf开始的位置空5(0x1000-0xFFB)字节。所以结合之前如果接收到exec才会跳转到这里,假设接收到的字符串为exec C/test.exe 那么CommandLine的值就为C/test.exe。所以这个.dll是一个后门程序。
.exe反汇编代码
首先argc是参数的个数,参数个数是2个。将第二个参数给eax,将指定字符串给esi。
将两字符串每一位进行逐一比较 。
mov edi, ds:CreateFileA
push eax ; hTemplateFile
push eax ; dwFlagsAndAttributes
push 3 ; dwCreationDisposition
push eax ; lpSecurityAttributes
push 1 ; dwShareMode
push 80000000h ; dwDesiredAccess
push offset FileName ; "C:\\Windows\\System32\\Kernel32.dll"
call edi ; CreateFileA //打开或者创建一个C:\\Windows\\System32\\Kernel32.dll
mov ebx, ds:CreateFileMappingA
push 0 ; lpName
push 0 ; dwMaximumSizeLow
push 0 ; dwMaximumSizeHigh
push 2 ; flProtect
push 0 ; lpFileMappingAttributes
push eax ; hFile
mov [esp+6Ch+hObject], eax
call ebx ; CreateFileMappingA
mov ebp, ds:MapViewOfFile
push 0 ; dwNumberOfBytesToMap
push 0 ; dwFileOffsetLow
push 0 ; dwFileOffsetHigh
push 4 ; dwDesiredAccess
push eax ; hFileMappingObject
call ebp ; MapViewOfFile
push 0 ; hTemplateFile
push 0 ; dwFlagsAndAttributes
push 3 ; dwCreationDisposition
push 0 ; lpSecurityAttributes
push 1 ; dwShareMode
mov esi, eax
push 10000000h ; dwDesiredAccess
push offset ExistingFileName ; "Lab07-03.dll"
mov [esp+70h+argc], esi
call edi ; CreateFileA
cmp eax, 0FFFFFFFFh
mov [esp+54h+var_4], eax
push 0 ; lpName
jnz short loc_401503
未完