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


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

    加密具体代码参考: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
    ", 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
    ");
    			}
    		}
    		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
    ",status);
    	printf("error is %d
    ", GetLastError());
    
    
    	if(status != NULL){
    		printf("7777777
    ");
    		//7、如果成功,将Src的PE文件拉伸 复制到该空间中
    		WriteProcessMemory(pi.hProcess, (LPVOID)dwBufferImageBaseSrc, pImageBufferSrc, dwBufferLengthSrc, NULL);
    
    	}else{
    		//8、如果申请空间失败,但有重定位表:在任意位置申请空间,然后将PE文件拉伸、复制、修复重定位表。
    		printf("8888888
    ");
    		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
    ",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
    ");
    			return -1;	
    		}
    	}
    
    
    	printf("10000000
    ");
    
    	
    	// 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;
    }
    

  • 相关阅读:
    cd 好吃的 收藏
    2011 无代码无意义…test 指针 v1
    转 云中漫步的 电子书 from simon
    2011无代码无意义 test_gets_scanf连用 等
    svn—relocate 的原因
    转 CString,string,char*的综合比较
    2011 无代码无意义 test_内存之 变量的边界 (图)
    转 解决"应用程序配置不正确,程序无法启动"
    转 删除已存在的SVN账户信息
    C#中IO类FileInfo和Directory操作实例
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/13228100.html
Copyright © 2020-2023  润新知