恶意软件API汇总(更新ing)
该地会汇总笔者在学习恶意样本分析过程中遇到的知名API,其中包括书上介绍的、实践分析过程中遇到的,会以功能为标题进行整理。
恶意代码分析实战
核心功能:窃密
击键记录
位置:恶意代码分析实战-11章-击键记录
功能:实现击键记录获取-登录凭证获取
函数名:
SetWindowsHookEx
、GetAsyncKeyState
和GetForegroundWindow
SetWindowsHookEx
介绍:函数功能:
SetWindowsHookEx
函数用于安装一个钩子过程,以监视和拦截特定的事件或消息。它允许你拦截和处理全局的鼠标、键盘、消息和其他系统事件。函数格式:
参数介绍:
idHook(int):指定要安装的钩子类型。它可以取以下值之一:
- WH_KEYBOARD:键盘钩子,用于监视键盘输入。
- WH_MOUSE:鼠标钩子,用于监视鼠标输入。
- WH_KEYBOARD_LL:低级键盘钩子,用于监视全局键盘输入。
- WH_MOUSE_LL:低级鼠标钩子,用于监视全局鼠标输入。
- 其他钩子类型,可以根据需要选择。
lpfn(HOOKPROC):指向钩子过程的指针。钩子过程是一个回调函数,当特定事件发生时,系统会调用此函数。钩子过程的具体实现根据钩子类型而异。
hMod(HINSTANCE):指定包含钩子过程的 DLL 的句柄。如果钩子过程位于当前进程的可执行文件中,可以传递 NULL。
dwThreadId(DWORD):标识要安装钩子的线程的线程标识符。如果要安装一个全局钩子,可以将此参数设置为 0,并且钩子过程将在所有线程上调用。
返回值:
如果函数成功,返回值是一个钩子的句柄(HHOOK)。如果函数失败,返回值为 NULL。
歌曰:安装钩子需要具有足够的权限,因此通常需要以管理员身份运行应用程序。
GetAsyncKeyState
函数函数功能:
GetAsyncKeyState
函数用于检索指定虚拟键的状态(按下或释放)。它可以用于获取当前键盘上某个键的状态,无论该键是否与当前活动窗口相关。函数格式:
1
2
3SHORT GetAsyncKeyState(
int vKey
);参数:
vKey
(int):指定要检索状态的虚拟键码。可以使用预定义的虚拟键码(如VK_RETURN
、VK_ESCAPE
等)或自定义虚拟键码。
返回值:
如果指定的虚拟键当前被按下,则返回值的最高位(MSB)被设置为1;如果指定的虚拟键当前未被按下,则返回值为0。对于返回值的其余位(除了最高位),它们是按下时返回的计数值,以指示键被按下的次数。
GetForegroundWindow
函数函数功能:
GetForegroundWindow
函数用于获取当前具有焦点的窗口的句柄。它返回当前活动窗口的句柄,即用户当前正在与之交互的窗口。函数格式:
1
HWND GetForegroundWindow();
参数:
- 无
返回值:
返回值是当前具有焦点的窗口的句柄(HWND)。如果没有窗口具有焦点,返回值为
NULL
。
资源节使用
位置:恶意代码分析实战-示例
功能:资源节隐藏载荷,进行读取与载入
函数:
FindResource、LoadResource、LockResource、SizeofResource、VirtualAlloc、FreeResource
以下是关于这些函数的介绍:
FindResource
函数:- 用途:在可执行文件(或 DLL)的资源表中查找指定的资源。
- 参数:
hModule
:指定包含资源的模块的句柄,通常是可执行文件或 DLL 的句柄。如果为NULL
,表示使用当前可执行文件或 DLL。lpName
:指定资源的名称或标识符。lpType
:指定资源的类型。
- 返回值:如果函数调用成功,返回指向资源的句柄;否则返回
NULL
。
LoadResource
函数:- 用途:加载指定资源的内容,返回资源的句柄。
- 参数:
hModule
:指定包含资源的模块的句柄,通常是可执行文件或 DLL 的句柄。如果为NULL
,表示使用当前可执行文件或 DLL。hResInfo
:指定资源的句柄,可以使用FindResource
函数获取。
- 返回值:如果函数调用成功,返回指向资源的句柄;否则返回
NULL
。
LockResource
函数:- 用途:锁定
LoadResource
返回的资源句柄,返回资源的指针。 - 参数:
hResData
:指向资源的句柄,通常是LoadResource
函数的返回值。
- 返回值:如果函数调用成功,返回指向资源数据的指针;否则返回
NULL
。
- 用途:锁定
SizeofResource
函数:- 用途:获取指定资源的大小。
- 参数:
hModule
:指定包含资源的模块的句柄,通常是可执行文件或 DLL 的句柄。如果为NULL
,表示使用当前可执行文件或 DLL。hResInfo
:指定资源的句柄,可以使用FindResource
函数获取。
- 返回值:如果函数调用成功,返回资源的大小;否则返回 0。
VirtualAlloc
函数:- 用途:在进程的虚拟地址空间中分配内存。
- 参数:
lpAddress
:指定要分配的内存的首选地址。如果为NULL
,系统将自动选择一个地址。dwSize
:指定要分配的内存的大小(以字节为单位)。flAllocationType
:指定内存分配的类型和属性,例如MEM_COMMIT
、MEM_RESERVE
、MEM_RESET
等。flProtect
:指定内存保护属性,例如PAGE_READWRITE
、PAGE_EXECUTE_READ
等。
- 返回值:如果函数调用成功,返回指向分配内存的首地址的指针;否则返回
NULL
。
FreeResource
函数:- 用途:释放由
FindResource
、LoadResource
和LockResource
函数加载的资源。 - 参数:
hResData
:指向资源的句柄,通常是LoadResource
函数的返回值。
- 返回值:无。
- 用途:释放由
这些函数通常在处理和操作可执行文件或 DLL 中的资源时使用。它们允许你查找、加载、访问和释放资源的内容。
实例:
文件操作
进程源文件的移动
主要用于源文件的替换操作,先把源文件放到temp目录下。涉及到的API有:
GetWindowsDirectoryA、GetTempPathA、 snprintf、MoveFileA
。
GetWindowsDirectoryA
:该函数用于获取 Windows 操作系统的安装目录。GetTempPathA
:该函数用于获取临时文件夹的路径。snprintf
:snprintf
是一个 C 标准库函数,用于将格式化的数据写入字符串缓冲区。MoveFileA
:该函数用于重命名或移动文件或目录。
网络下载到文件
用于从网络下载数据到指定文件,进行软件更新。
URLDownloadToFile
函数:
函数功能:它可以从指定的 URL 下载文件,并将其保存到本地文件系统中的指定位置。
函数格式:
1 | HRESULT URLDownloadToFile( |
函数参数:
pCaller
: 指向IUnknown
接口的指针,可以为NULL
。szURL
: 要下载的文件的 URL 地址。szFileName
: 下载的文件保存的本地路径和文件名。dwReserved
: 保留参数,必须为 0。lpfnCB
: 指向IBindStatusCallback
接口的指针,用于接收下载进度回调,可以为NULL
。
返回值:函数返回值为 HRESULT
类型的值,用于表示操作的结果。如果函数调用成功,返回值为 S_OK
,否则可能返回其他错误代码。
歌曰:URLDownloadToFile
函数已被标记为过时(deprecated),不推荐在新的应用程序中使用。在现代的 Windows 系统中,推荐使用更强大和灵活的网络库或框架,如 WinINet、WinHTTP、CURL
等来进行文件下载操作。
注册表操作
网络连接操作
进程操作
创建(挂起)- 进程替换、打开进程-获取句柄、遍历操作-搜索指定进程、创建线程-进程注入。
遍历操作-搜索指定进程
一般是
psapi.dll
提供的一组函数。可以查询系统中的进程和模块信息,这些函数可以用于编写诸如进程监视、进程注入、进程枚举等类型的系统工具和应用程序。
EnumProcesses
:枚举系统中正在运行的进程。EnumProcessModules
:枚举指定进程中加载的模块。GetModuleBaseName
:获取指定进程中模块的基本名称。GetModuleFileNameEx
:获取指定进程中模块的完整路径。GetModuleInformation
:获取指定进程中模块的详细信息。GetProcessImageFileName
:获取指定进程的可执行文件路径。GetProcessId
:获取指定进程的进程 ID。GetProcessTimes
:获取指定进程的运行时间和 CPU 时间等。
下面主要细致介绍下前三个函数:
EnumProcesses
函数介绍:函数功能:用于枚举系统中正在运行的进程。
函数格式:
1
2
3
4
5BOOL EnumProcesses(
DWORD *lpidProcess,
DWORD cb,
DWORD *lpcbNeeded
);函数参数:
lpidProcess
:指向一个接收进程 ID 列表的数组的指针。调用该函数时,数组将被填充为系统中正在运行的进程的 ID。每个进程 ID 都是一个DWORD
类型的值。cb
:指定lpidProcess
数组的大小,以字节为单位。lpcbNeeded
:指向一个变量的指针,用于接收函数执行所需的实际字节数。如果传入的cb
小于所需的大小,则此变量将包含所需的大小值
返回值:返回值为
BOOL
类型,表示函数执行的成功或失败。如果函数成功执行,则返回值为非零;如果函数失败,则返回值为零。实际例子:
EnumProcessModules
函数:函数功能:枚举指定进程中加载的模块(DLL),存储句柄。
函数格式:
1
2
3
4
5
6BOOL EnumProcessModules(
HANDLE hProcess,
HMODULE *lphModule,
DWORD cb,
LPDWORD lpcbNeeded
);函数参数:
hProcess
:指定要枚举模块的进程的句柄。通常使用OpenProcess
函数打开进程并获取句柄。lphModule
:指向存储模块句柄的数组的指针。调用该函数时,数组将被填充为进程中加载的模块的句柄。每个模块句柄是一个HMODULE
类型的值。cb
:指定lphModule
数组的大小,以字节为单位。lpcbNeeded
:指向一个变量的指针,用于接收函数执行所需的实际字节数。如果传入的cb
小于所需的大小,则此变量将包含所需的大小值。
返回值:返回值为
BOOL
类型,表示函数执行的成功或失败。如果函数成功执行,则返回值为非零;如果函数失败,则返回值为零。GetModuleBaseNameA
函数:函数功能:用于获取指定进程中模块的基本名称(即模块的文件名)
函数格式:
1
2
3
4
5
6DWORD GetModuleBaseNameA(
HANDLE hProcess,
HMODULE hModule,
LPSTR lpBaseName,
DWORD nSize
);函数参数:
hProcess
:指定要获取模块名称的进程的句柄。通常使用OpenProcess
函数打开进程并获取句柄。hModule
:指定要获取基本名称的模块的句柄。如果指定NULL
,则返回主模块(即进程的可执行文件)的基本名称。lpBaseName
:指向接收基本名称的字符缓冲区的指针。nSize
:指定接收基本名称的字符缓冲区的大小,以字节为单位。
返回值:返回值为
DWORD
类型,表示实际复制到缓冲区中的字符数,不包括终止 null 字符。如果函数失败,则返回值为 0。实践一下:
歌曰:
GetModuleBaseNameA
是 ANSI 版本的函数,适用于使用 ANSI 字符集的应用程序。如果需要使用 Unicode 字符集,可以使用GetModuleBaseNameW
函数。
进程创建与进程替换
这部分主要是进程替换过程中涉及的函数,包括:
CreateProcess
、VirtualAlloc
、WriteProcessMemory
、SetThreadContext
、RssumeThread
。
CreateProcess
函数:函数功能:用于创建新的进程。它可以创建一个新的进程并且启动执行指定的可执行文件。
函数格式:
1
2
3
4
5
6
7
8
9
10
11
12BOOL CreateProcess(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);函数参数:
lpApplicationName
:可执行文件的路径或文件名。lpCommandLine
:命令行参数。lpProcessAttributes
:进程对象的安全属性,可以为NULL
。lpThreadAttributes
:线程对象的安全属性,可以为NULL
。bInheritHandles
:指定新进程是否继承父进程的句柄。dwCreationFlags
:指定创建进程的标志和选项。dwCreationFlags
参数设置CREATE_SUSPENDED
标志表示挂起。lpEnvironment
:新进程的环境变量,可以为NULL
。lpCurrentDirectory
:新进程的当前工作目录,可以为NULL
。lpStartupInfo
:指向STARTUPINFOW
结构的指针,用于指定新进程的启动信息。lpProcessInformation
:指向PROCESS_INFORMATION
结构的指针,用于接收新进程的信息。
返回值:函数返回值为
BOOL
类型,表示函数调用是否成功。如果函数成功,返回值为TRUE
,否则返回值为FALSE
。VirtualAllocEx
函数函数功能:
VirtualAllocEx函数
用于在指定的外部进程中分配内存空间。它允许一个进程分配内存,而该内存可以在不同的进程之间共享。这个函数的常见用途之一是在远程进程中注入代码或数据。函数格式:
1
2
3
4
5
6
7LPVOID VirtualAllocEx(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);函数参数:
- hProcess:要分配内存的目标进程的句柄。
- lpAddress:指定分配内存的起始地址,如果为NULL,则由系统自动选择。
- dwSize:要分配的内存大小,以字节为单位。
- flAllocationType:内存分配类型的标志,指定内存的使用方式,例如MEM_COMMIT表示立即提交内存,MEM_RESERVE表示保留内存。
- flProtect:内存保护标志,指定内存区域的访问权限,例如PAGE_READWRITE表示可读写。
返回值:
VirtualAllocEx函数的返回值是分配的内存的起始地址。如果分配内存失败,返回值为NULL。可以使用GetLastError函数获取更多关于失败原因的信息。
WriteProcessMemory
函数函数功能:
WriteProcessMemory
函数用于在指定的外部进程中写入数据。它允许一个进程将数据写入其他进程的分配的内存空间。这个函数的常见用途之一是在远程进程中修改数据或注入代码。函数格式:
1
2
3
4
5
6
7BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);函数参数:
- hProcess:要写入数据的目标进程的句柄。
- lpBaseAddress:要写入数据的内存地址。
- lpBuffer:指向要写入的数据缓冲区的指针。
- nSize:要写入的数据大小,以字节为单位。
- lpNumberOfBytesWritten:指向保存实际写入字节数的变量的指针。
返回值:
WriteProcessMemory函数的返回值是一个BOOL类型的值,表示写入操作是否成功。如果写入成功,返回值为非零;如果写入失败,返回值为零。可以使用GetLastError函数获取更多关于失败原因的信息。
GetThreadContext
函数:函数功能:用于获取指定线程的上下文信息。
函数格式:
1
2
3
4BOOL GetThreadContext(
HANDLE hThread,
LPCONTEXT lpContext
);hThread
:要获取上下文信息的目标线程的句柄。lpContext
:指向CONTEXT
结构体的指针,用于接收线程的上下文信息。
流程:调用
GetThreadContext
函数时,传递目标线程的句柄和指向CONTEXT
结构体的指针。函数将填充指定的CONTEXT
结构体,以提供有关线程的寄存器值、标志寄存器状态、堆栈指针等信息。SetThreadContext
函数:函数功能:用于设置指定线程的上下文信息,包括寄存器值、标志位等。(在这里一般用于设置入口点)
函数格式:
1
2
3
4BOOL SetThreadContext(
HANDLE hThread,
const CONTEXT *lpContext
);函数参数:
hThread
:要设置上下文的线程句柄。lpContext
:指向CONTEXT
结构的指针,包含要设置的上下文信息。
返回值:函数返回值为
BOOL
类型,表示函数调用是否成功。如果函数成功,返回值为TRUE
,否则返回值为FALSE
。RssumeThread
函数:函数功能:用于恢复被挂起的线程的执行。
函数格式:
1
2
3DWORD ResumeThread(
HANDLE hThread
);函数参数:
hThread
:要恢复执行的线程句柄。
返回值:函数返回值为线程的先前挂起计数。如果函数调用失败,返回值为
DWORD
类型的错误代码。
总结:一般是连环使用,先是创建一个挂起的进程,之后清空数据再替换数据,然后修改入口点最后启动进程。
Createprocess
创建与上下文的扩展:
挂起态创建:
在使用该函数创建一个新的进程的时候,可以指定dwCreationFlags参数为4,表示挂起该进程,直到使用
RssumeThread
函数才进行执行;IpStartupinfo
参数介绍:该参数是一个结构体,指定新进程的启动信息。下面是该结构体的定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20typedef struct _STARTUPINFOA {
DWORD cb;
LPSTR lpReserved;
LPSTR lpDesktop;
LPSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOA, *LPSTARTUPINFOA;cb
:结构体的大小,以字节为单位,用于指定结构体的版本。lpReserved
:保留字段,未使用,应设置为NULL
。lpDesktop
:新进程要使用的桌面名称,通常为NULL
表示使用默认桌面。lpTitle
:新进程的窗口标题,可以为NULL
。dwX
、dwY
:新进程的初始窗口左上角的屏幕坐标。dwXSize
、dwYSize
:新进程的初始窗口的宽度和高度。dwXCountChars
、dwYCountChars
:新进程的控制台窗口的字符单元数。dwFillAttribute
:控制台窗口的填充属性。dwFlags
:指定启动标志,例如STARTF_USESHOWWINDOW
、STARTF_USESTDHANDLES
等。wShowWindow
:指定新进程的窗口如何显示,如SW_SHOW
、SW_HIDE
等。cbReserved2
、lpReserved2
:保留字段,未使用,应设置为 0 或NULL
。hStdInput
、hStdOutput
、hStdError
:指定新进程的标准输入、输出和错误句柄。
所以我们可以先以挂起态创建某进程,再修改该结构体内容。
IpProcessInformation
参数介绍:用于接收新进程的信息,该结构体定义如下:
1
2
3
4
5
6typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;hProcess
:新进程的句柄,用于操作和管理该进程。hThread
:新进程的主线程句柄,用于操作和管理该主线程。dwProcessId
:新进程的进程标识符(Process ID)。dwThreadId
:新进程的主线程标识符(Thread ID)。
IpContext
介绍:CONTEXT
结构体用于保存和描述线程的上下文信息,下面是结构体定义:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27typedef struct _CONTEXT {
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs;
DWORD EFlags;
DWORD Esp;
DWORD SegSs;
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT, *PCONTEXT;ContextFlags
:用于指定上下文中包含的特定标志。Dr0
至Dr7
:调试寄存器,用于保存调试相关的信息。FloatSave
:浮点寄存器的保存区域。SegGs
至SegSs
:段寄存器,用于保存段选择子。Edi
至Eax
:通用寄存器,用于保存通用数据。Ebp
:基址指针寄存器,指向当前栈帧的基址。Eip
:指令指针寄存器,存储下一条要执行的指令的地址。SegCs
:代码段寄存器,保存当前代码段的选择子。EFlags
:标志寄存器,包含了一些特定的控制和状态标志。Esp
:堆栈指针寄存器,指向当前栈顶的地址。SegSs
:堆栈段寄存器,保存当前堆栈段的选择子。ExtendedRegisters
:用于保存扩展寄存器的数据。
通过传递一个指向
CONTEXT
结构体的指针作为参数,可以获取或设置线程的上下文信息。这些信息包括寄存器的值、标志寄存器的状态、堆栈指针、代码指针等。
熊猫烧香样本
魔窟样本
Mydoom样本
大黄蜂样本
游蛇样本
写在最后:这是不断更新的一章,后续分析各种家族样本与书籍示例时都会学习到新的API,会以样本为分类进行记录。