滴水Win32练习壳(傀儡进程)的学习与实现

前言:花了一天时间写完之后,自己困惑了好久,因为自己不会用,一直没有看到视频中的演示过程,纠结许久,最后看了下前面的演示教程发现懂了。。。

学习感受:一种变相替换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;
}

posted @ 2020-07-03 22:09  zpchcbd  阅读(1089)  评论(2编辑  收藏  举报