1. windows API
1.1類型和匈牙利表示法
windows API使用的變量名會使用前綴來說明它的類型肾砂,是一種命名規(guī)范
1.2 句柄
在windows中表示一個打開的對象 如窗口凛膏、進(jìn)程墓猎、模塊、文件同廉、等待
用于引用一個對象符衔,不能對句柄進(jìn)行數(shù)學(xué)操作
1.3 文件系統(tǒng)函數(shù)
CreateFile https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
ReadFile WriteFile
CreateFileMapping 將文件加載到內(nèi)存中
MapViewOfFile 返回一個指向映射的基地址指針
1.4 特殊文件
共享文件
\servername\share
\?\servername\share \?表示禁用所有的字符串解析耀里,并允許訪問長文件名
通過名字空間訪問的文件
WinObj可查看windows下的名字空間
\.\ 為前綴的為win32設(shè)備名字空間 如\.\PhysicalDisk1
\Device\PhysicalDisk1
\Device\PhysicalMemory 直接訪問物理內(nèi)存
備用數(shù)據(jù)流
允許數(shù)據(jù)添加到一個已經(jīng)存在的NTFS文件上半等,只有訪問流時才顯示揍愁,可用于數(shù)據(jù)隱藏
normalFile.txt.Stream:$DATA 來命名
2 windows注冊表
用于保存操作系統(tǒng)和程序的配置信息
惡意代碼常用注冊表進(jìn)行長久駐留
- 根鍵 5個頂層節(jié)
- 子鍵 類似于子文件夾
- 鍵 類似于文件夾
- 值項 一個鍵值對
- 值或數(shù)據(jù) 存儲在注冊表項中的值或數(shù)據(jù)
2.1 根鍵
- HKEY_LOCAL_MACHINE(HKLM) 保存本地機(jī)器的全局設(shè)置
- HKEY_LOCAL_USER(HKCU) 保存當(dāng)前用戶特定的設(shè)置
- HKEY_CLASSES_ROOT 保存定義的類型信息
- HKEY_CONRRENT_CONFIG 保存當(dāng)前硬件的配置
- HKEY_USERS 定義默認(rèn)用戶、當(dāng)前用戶杀饵、新用戶的配置
比如
HKEY_LOCAL_MACHINE\SOFTWARE\Micsosoft\Windows\CurrentVersion\Run 包含開機(jī)啟動項
2.2 Regedit
windows自帶的注冊表編輯器
2.3 自啟動程序
使用Autoruns可查看windows啟動時會自動啟動的代碼
下載地址 https://download.sysinternals.com/files/Autoruns.zip
2.4 常用注冊表函數(shù)
- RegOpenKeyEx 打開一個注冊表頂進(jìn)行編輯或查詢
- RegSetValueEx 設(shè)置注冊表項值
- RegGetValue 獲取注冊表項的值
2.5 使用.reg文件的注冊表腳本
.reg文件可用于修改注冊表
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"SecurityHealth"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,\
73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,53,00,65,00,63,00,75,\
00,72,00,69,00,74,00,79,00,48,00,65,00,61,00,6c,00,74,00,68,00,53,00,79,00,\
73,00,74,00,72,00,61,00,79,00,2e,00,65,00,78,00,65,00,00,00
"IgfxTray"="\"C:\\Windows\\system32\\igfxtray.exe\""
"HotKeysCmds"="\"C:\\Windows\\system32\\hkcmd.exe\""
"Persistence"="\"C:\\Windows\\system32\\igfxpers.exe\""
3 網(wǎng)絡(luò)API
3.1 伯克利兼容套接字
windows winsock套接字 由ws2_32.dll提供
服務(wù)器端
1、調(diào)用socket打開一個socket句柄
2谬擦、調(diào)用bind來綁定socket句柄到一個網(wǎng)口的某個端口
3切距、調(diào)用listen來設(shè)置(啟用)監(jiān)聽
4、調(diào)用accept來等待客戶端的連接
客戶端
1惨远、先是使用socket函數(shù)產(chǎn)生一個打開的socket文件描述符谜悟。
2、使用connect函數(shù)去連接服務(wù)端
3北秽、使用read/recv等讀文件函數(shù)從服務(wù)端接收數(shù)據(jù)葡幸,使用write/send等寫文件的函數(shù)向服務(wù)端發(fā)送數(shù)據(jù)
程序的大致框架
1、初始化
/加載Winsock DLL/
WSADATA wsd;
if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
printf("Winsock 初始化失敗!\n");
return 1;
}
2贺氓、socket相關(guān)函數(shù)調(diào)用
socket(...)
bind(...)
listen(...)
connect(...)
accept(...)
send/sendto
recv/recvfrom
3蔚叨、清理
WSACleanup();
可參考https://www.cnblogs.com/oloroso/p/4613296.html
一個簡單的tcp_client的例子
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//tcp socket客戶端
//鏈接ws2_32.lib這個庫
#pragma comment(lib , "ws2_32.lib")
#define BUFSIZE 4096 /*緩沖區(qū)大小*/
int main(int argc , char *argv[])
{
WSADATA wsd;
SOCKET sClient;
char* Buffer[BUFSIZE];
int ret;
struct sockaddr_in server;
unsigned short port;
struct hostent *host = NULL;
/*加載Winsock DLL*/
if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
printf("Winsock 初始化失敗!\n");
return 1;
}
/*創(chuàng)建Socket*/
sClient = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
if (sClient == INVALID_SOCKET) {
printf("socket() 失敗: %d\n" , WSAGetLastError());
return 1;
}
/*指定服務(wù)器地址*/
server.sin_family = AF_INET;
port = atoi(argv[2]);
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(argv[1]);
if (server.sin_addr.s_addr == INADDR_NONE) {
host = gethostbyname(argv[1]); //輸入的地址可能是域名等
if (host == NULL) {
printf("無法解析服務(wù)端地址: %s\n" , argv[1]);
return 1;
}
CopyMemory(&server.sin_addr ,
host->h_addr_list[0] ,
host->h_length);
}
/*與服務(wù)器建立連接*/
if (connect(sClient , (struct sockaddr*)&server ,
sizeof(server)) == SOCKET_ERROR) {
printf("connect() 失敗: %d\n" , WSAGetLastError());
return 1;
}
/*發(fā)送、接收消息*/
for (;;) {
//從標(biāo)準(zhǔn)輸入讀取要發(fā)送的數(shù)據(jù)
//gets_s(Buffer,BUFSIZE);
gets(Buffer);
strcat(Buffer,"\r\n\r\n");
//向服務(wù)器發(fā)送消息
ret = send(sClient , Buffer , strlen(Buffer) , 0);
if (ret == 0) {
break;
}
else if (ret == SOCKET_ERROR) {
printf("send() 失敗: %d\n" , WSAGetLastError());
break;
}
printf("Send %d bytes\n" , ret);
//接收從服務(wù)器來的消息
ret = recv(sClient , Buffer , BUFSIZE , 0);
if (ret == 0) {
break;
}
else if (ret == SOCKET_ERROR) {
printf("recv() 失敗: %d\n" , WSAGetLastError());
break;
}
Buffer[ret] = '\0';
printf("Recv %d bytes:\n\t%s\n" , ret , Buffer);
}
//用完了辙培,關(guān)閉socket句柄(文件描述符)
closesocket(sClient);
WSACleanup(); //清理
return 0;
}
使用
3.3 WinINet API
更高一級的網(wǎng)絡(luò)API 實現(xiàn)了HTTP和ftp協(xié)議
- InternetOpen
- InternetOpenUrl
- InternetReadFile
更多可參考 https://www.cnblogs.com/fuchongjundream/p/3853716.html
1蔑水、普通 WinInet 處理函數(shù)
⊙ InetrnetOpen 初始化 WinInet.dll
⊙ InternetOpenUrl 打開 Url,讀取數(shù)據(jù)
⊙ InternetAttemptConnect 嘗試建立到 Internet 的連接
⊙ InternetConnect 建立 Internet 的連接
⊙ InternetCheckConnection 檢查 Internet 的連接是否能夠建立
⊙ InternetSetOption 設(shè)置一個 Internet 選項
⊙ InternetSetStausCallback 安裝一個回調(diào)函數(shù)扬蕊,供 API 函數(shù)調(diào)用
⊙ InternetQueryOption 查詢在一個指定句柄上的 Internet 選項
⊙ InternetQueryDataAvailable 查詢可用數(shù)據(jù)的數(shù)量
⊙ InternetReadFile(Ex) 從一個打開的句柄讀取數(shù)據(jù)
⊙ InternetFindNextFile 繼續(xù)文件搜尋
⊙ InetrnetSetFilePointer 為 InternetReadFile 設(shè)置一個文件位置
⊙ InternetWriteFile 將數(shù)據(jù)寫到一個打開的 Internet 文件
⊙ InternetLockRequestFile 允許用戶為正在使用的文件加鎖
⊙ InternetUnlockRequestFile 解鎖被鎖定的文件
⊙ InternetTimeFromSystemTime 根據(jù)指定的 RFC 格式格式化日期和時間
⊙ InternetTimeToSystemTime 將一個 HTTP 時間/日期字串格式化為 SystemTime 結(jié)構(gòu)對象
⊙ InternetConfirmZoneCrossing 檢查在安全 URL 和非安全 URL 間的變化
⊙ InternetCloseHandle 關(guān)閉一個單一的 Internet 句柄
⊙ InternetErrorDlg 顯示錯誤信息對話框
⊙ InternetGetLastResponesInfo 獲取最近發(fā)送的 API函數(shù)的錯誤
2搀别、HTTP 處理函數(shù)
⊙ HttpOpenRequest 打開一個 HTTP 請求的句柄
⊙ HttpSendRequert(Ex) 向 HTTP 服務(wù)器發(fā)送指定的請求
⊙ HttpQueryInfo 查詢有關(guān)一次 HTTP 請求的信息
⊙ HttpEndRequest 結(jié)束一個 HTTP 請求
⊙ HttpAddRequestHeaders 添加一個或多個 HTTP 請求報頭到 HTTP請求句柄
3、FTP 處理函數(shù)
⊙ FtpCreateDirectory 在 Ftp 服務(wù)器新建一個目錄
⊙ FtpDelectFile 刪除存儲在 Ftp 服務(wù)器上的文件
⊙ FtpFindFirstFile 查找給定 Ftp 會話中的指定目錄
⊙ FtpGetCurrentDirectory 為指定 Ftp 會話獲取當(dāng)前目錄
⊙ FtpGetFile 從 Ftp 服務(wù)器下載文件
⊙ FtpOpenFile 訪問一個遠(yuǎn)程文件以對其進(jìn)行讀寫
⊙ FtpPutFile 向 Ftp 服務(wù)器上傳文件
⊙ FtpRemoveDirectory 在 Ftp 服務(wù)器刪除指定的文件
⊙ FtpRenameFile 為 Ftp 服務(wù)器上的指定文件改名
⊙ FtpSetCurrentDirectory 更改在 Ftp 服務(wù)器上正在使用的目錄
4 跟蹤惡意代碼的運(yùn)行
4.1 DLL
dll用于在多個windows程序間共享代碼 在內(nèi)存中可以被不同的程序共享使用
惡意代碼如何使用dll
- 保存惡意代碼
- 通過使用windows dll
- 使用第三方的dll
4.2 進(jìn)程
進(jìn)程之間共享系統(tǒng)資源互不干擾
進(jìn)程使用的的邏輯地址可相同尾抑,但是映射的物理地址不同
創(chuàng)建新進(jìn)程
- CreateProcess https://docs.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
4.3 線程
一個進(jìn)程可包含多個線程歇父,這些線程共享內(nèi)存空間蒂培,但是第一個擁有自己的處理器、寄存器和棧
線程上下文
操作系統(tǒng)在切換線程時榜苫,會將CPU中的所有值存儲在線程上下文這個結(jié)構(gòu)體中毁渗。輪到該線程時,會重啟加載該線程上下文单刁,恢復(fù)寄存器的值
創(chuàng)建一個線程
- CreateThread
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // NULL
SIZE_T dwStackSize,//0
LPTHREAD_START_ROUTINE lpStartAddress,//線程函數(shù)的地址
__drv_aliasesMem LPVOID lpParameter,//線程函數(shù)的參數(shù)
DWORD dwCreationFlags,//啟動方式 0
LPDWORD lpThreadId//用來接收線程掃描符
);//返回線程的handle
lpStartAddress 原型為
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
如何創(chuàng)建線程可參數(shù)MSDN上的例子 https://docs.microsoft.com/zh-cn/windows/win32/procthread/creating-threads?redirectedfrom=MSDN
惡意代碼的用法
- 通過CreateThead加載新的惡意代碼庫到進(jìn)程中
- 為輸入和輸出創(chuàng)建出個線程 一個讀取命令灸异,一個返回結(jié)果
windows系統(tǒng)中還有纖程,纖程與線程類似羔飞,但是被一個線程管理肺樟,而不是操作系統(tǒng),纖程共享單一的線程上下文逻淌。
4.4 使用互斥量在進(jìn)程間協(xié)作
互斥量為全局對象么伯,用于協(xié)調(diào)多個進(jìn)程和線程,用于控制資源的訪問
WaitForSingleObject獲取互斥量
ReleaseMutex釋放互斥量
可以通過CreateMutex函數(shù)創(chuàng)建互斥量卡儒,通過OpenMutex來獲取另一個進(jìn)程中互斥量的句柄
惡意代碼通常會創(chuàng)建一個互斥量田柔,并試圖用同一名稱打開一個已經(jīng)存在的互斥量,來確定是否有自身實例在運(yùn)行
4.5 服務(wù)
windows程序允許使用服務(wù)來使程序后臺運(yùn)行骨望,代碼被windows服務(wù)管理器調(diào)度和運(yùn)行
可用于惡意代碼的長久駐留 可獲取 system賬戶權(quán)限 比較隱蔽
相關(guān)API
- OpenSCManager 打開服務(wù)管理器
- CreateService 創(chuàng)建服務(wù)
- StartService 啟動服務(wù)
服務(wù)類型
- WIN32_SHARE_PROCESS 將服務(wù)的代碼放在一個dll中硬爆,在一個共享的進(jìn)程中組合不同的服務(wù)
- WIN32_OWN_PROCESS 在一個.exe中保存代碼,作為一個進(jìn)程來運(yùn)行
- KERNEL_DRIVER 用來加載代碼到內(nèi)核
本地服務(wù)被保存在注冊表中擎鸠,每個服務(wù)在HKLM\SYSTEM\CurrentControlSet\Services下有一個字鍵
sc命令可用于添加缀磕、刪除、啟動劣光、停止袜蚕、查詢服務(wù)
描述:
SC 是用來與服務(wù)控制管理器和服務(wù)進(jìn)行通信
的命令行程序。
用法:
sc <server> [command] [service name] <option1> <option2>...
<server> 選項的格式為 "\\ServerName"
可通過鍵入以下命令獲取有關(guān)命令的更多幫助: "sc [command]"
命令:
query-----------查詢服務(wù)的狀態(tài)绢涡,
或枚舉服務(wù)類型的狀態(tài)牲剃。
queryex---------查詢服務(wù)的擴(kuò)展?fàn)顟B(tài),
或枚舉服務(wù)類型的狀態(tài)雄可。
start-----------啟動服務(wù)凿傅。
pause-----------向服務(wù)發(fā)送 PAUSE 控制請求。
interrogate-----向服務(wù)發(fā)送 INTERROGATE 控制請求滞项。
continue--------向服務(wù)發(fā)送 CONTINUE 控制請求狭归。
stop------------向服務(wù)發(fā)送 STOP 請求。
config----------更改服務(wù)的配置(永久)文判。
description-----更改服務(wù)的描述过椎。
failure---------更改失敗時服務(wù)執(zhí)行的操作。
failureflag-----更改服務(wù)的失敗操作標(biāo)志戏仓。
sidtype---------更改服務(wù)的服務(wù) SID 類型疚宇。
privs-----------更改服務(wù)的所需特權(quán)亡鼠。
managedaccount--更改服務(wù)以將服務(wù)帳戶密碼
標(biāo)記為由 LSA 管理。
qc--------------查詢服務(wù)的配置信息敷待。
qdescription----查詢服務(wù)的描述间涵。
qfailure--------查詢失敗時服務(wù)執(zhí)行的操作。
qfailureflag----查詢服務(wù)的失敗操作標(biāo)志榜揖。
qsidtype--------查詢服務(wù)的服務(wù) SID 類型勾哩。
qprivs----------查詢服務(wù)的所需特權(quán)。
qtriggerinfo----查詢服務(wù)的觸發(fā)器參數(shù)举哟。
qpreferrednode--查詢服務(wù)的首選 NUMA 節(jié)點思劳。
qmanagedaccount-查詢服務(wù)是否將帳戶
與 LSA 管理的密碼結(jié)合使用。
qprotection-----查詢服務(wù)的進(jìn)程保護(hù)級別妨猩。
quserservice----查詢用戶服務(wù)模板的本地實例潜叛。
delete ----------(從注冊表中)刪除服務(wù)。
create----------創(chuàng)建服務(wù)(并將其添加到注冊表中)壶硅。
control---------向服務(wù)發(fā)送控制威兜。
sdshow----------顯示服務(wù)的安全描述符。
sdset-----------設(shè)置服務(wù)的安全描述符庐椒。
showsid---------顯示與任意名稱對應(yīng)的服務(wù) SID 字符串椒舵。
triggerinfo-----配置服務(wù)的觸發(fā)器參數(shù)。
preferrednode---設(shè)置服務(wù)的首選 NUMA 節(jié)點扼睬。
GetDisplayName--獲取服務(wù)的 DisplayName逮栅。
GetKeyName------獲取服務(wù)的 ServiceKeyName。
EnumDepend------枚舉服務(wù)依賴關(guān)系窗宇。
以下命令不需要服務(wù)名稱:
sc <server> <command> <option>
boot------------(ok | bad)指示是否應(yīng)將上一次啟動另存為
最近一次已知的正確啟動配置
Lock------------鎖定服務(wù)數(shù)據(jù)庫
QueryLock-------查詢 SCManager 數(shù)據(jù)庫的 LockStatus
示例:
sc start MyService
QUERY 和 QUERYEX 選項:
如果查詢命令帶服務(wù)名稱,將返回
該服務(wù)的狀態(tài)特纤。其他選項不適合這種
情況军俊。如果查詢命令不帶參數(shù)或
帶下列選項之一,將枚舉此服務(wù)捧存。
type= 要枚舉的服務(wù)的類型(driver, service, userservice, all)
(默認(rèn) = service)
state= 要枚舉的服務(wù)的狀態(tài) (inactive, all)
(默認(rèn) = active)
bufsize= 枚舉緩沖區(qū)的大小(以字節(jié)計)
(默認(rèn) = 4096)
ri= 開始枚舉的恢復(fù)索引號
(默認(rèn) = 0)
group= 要枚舉的服務(wù)組
(默認(rèn) = all groups)
語法示例
sc query - 枚舉活動服務(wù)和驅(qū)動程序的狀態(tài)
sc query eventlog - 顯示 eventlog 服務(wù)的狀態(tài)
sc queryex eventlog - 顯示 eventlog 服務(wù)的擴(kuò)展?fàn)顟B(tài)
sc query type= driver - 僅枚舉活動驅(qū)動程序
sc query type= service - 僅枚舉 Win32 服務(wù)
sc query state= all - 枚舉所有服務(wù)和驅(qū)動程序
sc query bufsize= 50 - 枚舉緩沖區(qū)為 50 字節(jié)
sc query ri= 14 - 枚舉時恢復(fù)索引 = 14
sc queryex group= "" - 枚舉不在組內(nèi)的活動服務(wù)
sc query type= interact - 枚舉所有不活動服務(wù)
sc query type= driver group= NDIS - 枚舉所有 NDIS 驅(qū)動程序
4.6 組件對象模型
COM是一種接口標(biāo)準(zhǔn)粪躬,使用C-S模式,客戶端為使用COM組件的程序昔穴,服務(wù)端為可利用的軟件組件 即COM對象本身
一般客戶端程序需要使用OleInitialize和CoInitializeEx
COM對象的使用
Com對象通過它們的全局唯一標(biāo)識符GUID來訪問 分為類型標(biāo)識符(CLSID)和接口標(biāo)識符(IID)
Navigate函數(shù)可打開 Internet Explorer 訪問網(wǎng)址
CoCreateInstance 會返回一個結(jié)構(gòu)體镰官,其中含有函數(shù)地址
COM服務(wù)器惡意代碼
實現(xiàn)一個COM服務(wù)器相關(guān)API
- DllCanUnloadNow
- DllGetClassObject
- DllInstall
- DllRegisterServer
- DllUnregisterServer
4.7 異常處理
沒看懂
5 內(nèi)核與用戶模式
操作系統(tǒng)和硬件驅(qū)動運(yùn)行在內(nèi)核模式,所有運(yùn)行在內(nèi)核模式的程序共享資源 和內(nèi)存地址
運(yùn)行在內(nèi)核中的代碼可以操縱用戶空間的代碼,用戶空間的代碼直接通過給定的接口來影響內(nèi)核
大多數(shù)的反病毒軟件和防火墻都運(yùn)行在內(nèi)核模式,用于監(jiān)控系統(tǒng)上所有程序的運(yùn)行,運(yùn)行在內(nèi)核模式的代碼可以繞過安全程序
rootkit
6 原生API
原生API是底層api
微軟不提供原生api的文檔, 但是可以在這個網(wǎng)站查詢
http://undocumented.ntinternals.net/
惡意代碼調(diào)用原生API可以繞過檢測