前言:花了一天時間寫完之后,自己困惑了好久,因為自己不會用,一直沒有看到視頻中的演示過程,糾結許久,最后看了下前面的演示教程發現懂了。。。
學習感受:一種變相替換CreateProcess所要運行的進程的方法,這個方法被稱作為“傀儡進程”
加密具體代碼參考:https://github.com/adezz/PeDialog
解密具體代碼參考:https://github.com/adezz/Shell-Of-Water
加密實現:
void AddWaterShell(){
//--------------------------------------加密過程--------------------------------------
TCHAR szBufferSrc[MAX_PATH];
TCHAR szBufferShell[MAX_PATH];
TCHAR* szBufferNew;
memset(szBufferSrc,0,MAX_PATH);
memset(szBufferShell,0,MAX_PATH);
PVOID pFileBufferSrc = NULL;
PVOID pFileBufferShell = NULL;
PVOID pFileNewBufferShell = NULL;
DWORD dwBufferLengthSrc = 0;
DWORD dwBufferLengthShell = 0;
GetWindowText(hShellEdit1,szBufferShell,MAX_PATH); // shell file
GetWindowText(hShellEdit2,szBufferSrc,MAX_PATH); // shell file
MyReadFile(&pFileBufferSrc,&dwBufferLengthSrc,szBufferSrc); //src
XorEncryptAAA((char*)pFileBufferSrc,dwBufferLengthSrc);
MyReadFile(&pFileBufferShell,&dwBufferLengthShell,szBufferShell);// shell
ShellAddNewSectionAndData(pFileBufferShell, &dwBufferLengthShell, &pFileNewBufferShell, pFileBufferSrc, dwBufferLengthSrc); // (1) 定為到SHELL文件的最后一個節
szBufferNew = &szBufferShell[0];
strcat(szBufferNew, ".exe");
MyWriteFile(pFileNewBufferShell,dwBufferLengthShell, szBufferNew);
}
殼源程序(解密):
int main(int argc, char* argv[])
{
//--------------------------------------解密過程--------------------------------------
//獲取當前程序運行路徑
char FilePathSelf[255] = {0};
GetModuleFileName(NULL, FilePathSelf, 255);
// 1、讀取當前殼子程序本身 數據
PVOID pFileBufferShell = NULL;
DWORD dwBufferLengthShell = 0;
MyReadFile(&pFileBufferShell,&dwBufferLengthShell,FilePathSelf);
// 2、解密源文件,獲取源文件的imagebase sizeofimage數據
PVOID pFileBufferSrc = NULL;
DWORD dwBufferLengthSrc = 0;
DWORD dwBufferImageBaseSrc = 0;
// dwBufferLengthSrc = GetSizeOfImage(pFileBufferShell);
GetSrcDataFromShell(pFileBufferShell, &pFileBufferSrc, &dwBufferLengthSrc,&dwBufferImageBaseSrc);
// 3、拉伸PE pImageBufferSrc
PVOID pImageBufferSrc = NULL;
CopyFileBufferToImageBuffer(pFileBufferSrc,&pImageBufferSrc);
// 4、以掛起方式運行殼程序進程
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
::CreateProcess(FilePathSelf,NULL,NULL,NULL,NULL,CREATE_SUSPENDED, NULL,NULL,&si,&pi);
printf("error is %d\n", GetLastError());
DWORD dwImageBaseShell = GetImageBase(pFileBufferShell); // 獲取殼子程序自身的imagebase
//5、卸載外殼程序的文件鏡像
typedef long NTSTATUS;
typedef NTSTATUS(__stdcall *pfnZwUnmapViewOfSection)(unsigned long ProcessHandle, unsigned long BaseAddress);
pfnZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
HMODULE hModule = LoadLibrary("ntdll.dll");
if(hModule){
ZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)GetProcAddress(hModule, "ZwUnmapViewOfSection");
if(ZwUnmapViewOfSection){
if(ZwUnmapViewOfSection((unsigned long)pi.hProcess, dwImageBaseShell)){ // 卸載掉 殼子程序自身的ImageBase 地址
printf("ZwUnmapViewOfSection success\n");
}
}
FreeLibrary(hModule);
}
//6、在指定的位置(src的ImageBase)申請指定大小(src的SizeOfImage)的內存(VirtualAllocEx)
LPVOID status = NULL;
status = VirtualAllocEx(pi.hProcess, (LPVOID)dwBufferImageBaseSrc,dwBufferLengthSrc,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
printf("VirtualAllocEx: %x\n",status);
printf("error is %d\n", GetLastError());
if(status != NULL){
printf("7777777\n");
//7、如果成功,將Src的PE文件拉伸 復制到該空間中
WriteProcessMemory(pi.hProcess, (LPVOID)dwBufferImageBaseSrc, pImageBufferSrc, dwBufferLengthSrc, NULL);
}else{
//8、如果申請空間失敗,但有重定位表:在任意位置申請空間,然后將PE文件拉伸、復制、修復重定位表。
printf("8888888\n");
PIMAGE_BASE_RELOCATION pRelocationDirectory = NULL;
DWORD pRelocationDirectoryVirtual = 0;
DWORD NumberOfRelocation;
PWORD Location;
DWORD RVA_Data;
WORD reloData;
DWORD FOA;
DWORD dwTempImageBaseSrc = dwBufferImageBaseSrc + 0x50000;
pRelocationDirectoryVirtual = GetRelocationTable(pFileBufferSrc); //當前重定位表的虛擬地址
printf("%x\n",pRelocationDirectoryVirtual);
if(pRelocationDirectoryVirtual){
RVA_TO_FOA(pFileBufferSrc, pRelocationDirectoryVirtual, &FOA);
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBufferSrc + FOA);
//申請空間
status = VirtualAllocEx(pi.hProcess, (LPVOID)dwTempImageBaseSrc,dwBufferLengthSrc,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
ChangesImageBase(pFileBufferSrc, dwTempImageBaseSrc);
WriteProcessMemory(pi.hProcess, (LPVOID)dwTempImageBaseSrc, pImageBufferSrc, dwBufferLengthSrc, NULL);
while(pRelocationDirectory->SizeOfBlock && pRelocationDirectory->VirtualAddress){
NumberOfRelocation = (pRelocationDirectory->SizeOfBlock - 8)/2;// 每個重定位塊中的數據項的數量
Location = (PWORD)((DWORD)pRelocationDirectory + 8); // 加上8個字節
for(DWORD i=0;i<NumberOfRelocation;i++){
if(Location[i] >> 12 != 0){ //判斷是否是垃圾數據
// WORD類型的變量進行接收
reloData = (Location[i] & 0xFFF); //這里進行與操作 只取4字節 二進制的后12位
RVA_Data = pRelocationDirectory->VirtualAddress + reloData; //這個是RVA的地址
RVA_TO_FOA(pFileBufferSrc,RVA_Data,&FOA);
//這里是自增的 進行修復重定位,上面的Imagebase我們改成了TempImageBase,那么改變的值就是 TempImageBase-dwBufferImageBaseSrc
*(PDWORD)((DWORD)pFileBufferSrc+(DWORD)FOA) = *(PDWORD)((DWORD)pFileBufferSrc+(DWORD)FOA) + dwTempImageBaseSrc - dwBufferImageBaseSrc; // 任意位置 - Origin ImageBase
}
}
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationDirectory + (DWORD)pRelocationDirectory->SizeOfBlock); //上面的for循環完成之后,跳轉到下個重定位塊 繼續如上的操作
}
dwBufferImageBaseSrc = dwTempImageBaseSrc;
}else{
// 9、如果第6步申請空間失敗,並且還沒有重定位表,直接返回:失敗.
printf("999999\n");
return -1;
}
}
printf("10000000\n");
// 10、修改外殼程序的Context:
CONTEXT cont;
cont.ContextFlags = CONTEXT_FULL;
::GetThreadContext(pi.hThread, &cont);
DWORD dwEntryPoint = GetOep(pFileBufferSrc); // get oep
cont.Eax = dwEntryPoint + dwBufferImageBaseSrc; // set origin oep
DWORD theOep = cont.Ebx + 8;
DWORD dwBytes=0;
WriteProcessMemory(pi.hProcess, &theOep, &dwBufferImageBaseSrc,4, &dwBytes);
SetThreadContext(pi.hThread, &cont);
//記得恢復線程
ResumeThread(pi.hThread);
ExitProcess(0);
return 0;
}