首页
社区
课程
招聘
[求助]滴水三期 壳子代码,请问大佬们,为啥会蓝屏啊
发表于: 2025-6-21 16:26 290

[求助]滴水三期 壳子代码,请问大佬们,为啥会蓝屏啊

2025-6-21 16:26
290

这里我试过了 加密,解密后拉伸,然后写到文件,没有问题,卸载过后,分配空间也没有问题,就是指定eip后蓝屏

void* shell::decryption(void* pePtr) {

	// 读取这个壳程序最后的一个节
	// 解密这个最后一个节
	// 读取这个最后一个节,拉伸,并获取关键信息
	// 开启一个新进程,挂起
	// 获取线程上下文
	// 卸载外壳程序的文件镜像(ZwUnmapViewOfSection)
	// 在指定的位置(src的ImageBase)申请指定大小(src的SizeOfImage)的内存(VirtualAllocEx)
	// 如果创建失败,查看src是否包含重定位表,如果包含重定位表,就在任意位置申请(src的SizeOfImage)大小的内存,然后修复重定位表.
	// 如果在指定位置申请内存失败,并且没有重定位表的数据,直接返回失败.
	// 如果内存申请成功,将新的数据复制到内存中 
	// 修正运行环境的基址和入口地址 
	// 恢复运行

	IMAGE_SECTION_HEADER* sectionStart = getSectionHeadStart(pePtr);
	DWORD numberOfSection = getNumberOfSections(pePtr);
	IMAGE_SECTION_HEADER* lastSectionStart = sectionStart + (numberOfSection - 1);
	char* decodeSrcPtr = (char*)((DWORD)pePtr + lastSectionStart->PointerToRawData);
	DWORD encodeSrcSize = lastSectionStart->SizeOfRawData >= lastSectionStart->Misc.VirtualSize ? lastSectionStart->SizeOfRawData : lastSectionStart->Misc.VirtualSize;
	// 解密
	for (int i = 0; i < encodeSrcSize; i++) {
		*(decodeSrcPtr + i) ^= 0x66;
	}

	// 拉伸
	void* srcPePtr = stretchFile((void*)decodeSrcPtr);
	// 挂起方式启动一个EXE
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi;
	si.cb = sizeof(STARTUPINFO);
	TCHAR szBuffer[256] = TEXT("C:\\Windows\\SysWOW64\\notepad.exe");
	CreateProcess(szBuffer, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
	CONTEXT contx;
	contx.ContextFlags = CONTEXT_FULL;
	GetThreadContext(pi.hThread, &contx);

	// 卸载
	typedef LONG(WINAPI* ZWUNMAPVIEWOFSECTION)(HANDLE, PVOID);
	ZWUNMAPVIEWOFSECTION ZwUnmapViewOfSection =
		(ZWUNMAPVIEWOFSECTION)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "ZwUnmapViewOfSection");
	PVOID baseAddress = GetRemoteImageBase(pi.hProcess);
	LONG status = ZwUnmapViewOfSection(pi.hProcess, baseAddress);
	if (status != 0) {
		std::cout << "ZwUnmapViewOfSection failed, status: " << std::hex << status << "\n";
		return NULL;
	}

	std::cout << "映像卸载成功,现在可以 VirtualAllocEx + WriteProcessMemory 写入你解密的PE 了。\n";

	DWORD srcImageBase = getImageBase(srcPePtr);

	DWORD fullSize = getSizeOfImage(srcPePtr);
	DWORD oep = getOEPPoint(srcPePtr);
	//分配空间
	LPVOID allocAddress = VirtualAllocEx(
		pi.hProcess,            // pi 是 PROCESS_INFORMATION 中的进程句柄
		(LPVOID)srcImageBase,              // 建议分配的地址(可以是 imageBase 或 NULL)
		fullSize,                 // 映像大小(从原始 PE 文件读取)
		MEM_COMMIT | MEM_RESERVE,
		PAGE_EXECUTE_READWRITE  // 可读可写可执行
	);

	if (!allocAddress) {
		std::cout << "VirtualAllocEx 失败,错误码:" << GetLastError() << std::endl;
		// 判断是否有重定位表,如果有重定位表,就随机分配空间,没有重定位表直接报错
		//分配空间
		allocAddress = VirtualAllocEx(
			pi.hProcess,            // pi 是 PROCESS_INFORMATION 中的进程句柄
			NULL,              // 建议分配的地址(可以是 imageBase 或 NULL) NULL 是随机分配
			fullSize,                 // 映像大小(从原始 PE 文件读取)
			MEM_COMMIT | MEM_RESERVE,
			PAGE_EXECUTE_READWRITE  // 可读可写可执行
		);
		boolean flag = rebuildRelocationTable(srcPePtr, (DWORD)allocAddress);
		if (flag == FALSE) {
			return NULL;
		}
	
	}
	else {
		std::cout << "在目标进程中分配内存成功,地址:" << allocAddress << std::endl;
	}

	// 写入新开辟的内存中
	SIZE_T bytesWritten = 0;
	BOOL success = WriteProcessMemory(pi.hProcess,  // 目标进程句柄
		allocAddress,// 远程进程中要写入的地址
		srcPePtr,// 本地缓冲区(解密后的原始 PE 文件)
		fullSize, // 要写入的字节数(完整映像)
		&bytesWritten);
	if (!success || bytesWritten != fullSize) {
		std::cout << "写入失败,写入字节:" << bytesWritten << " / " << fullSize << std::endl;
		return NULL;
	}
	else {
		std::cout << "写入成功,已经将原始程序写入目标进程!" << std::endl;
	}
	FlushInstructionCache(pi.hProcess, allocAddress, fullSize);
	// 修正 Eip(或 Rip)到新的入口
	DWORD_PTR newBase = (DWORD_PTR)allocAddress;
#ifdef _WIN64
	contx.Rip = (DWORD64)newBase + oep;
#else
	contx.Eip = (DWORD)newBase + oep;
	contx.Eax = (DWORD)newBase + oep;
#endif


	// 把修改后的上下文设置回线程
	SetThreadContext(pi.hThread, &contx);

	// 恢复挂起线程
	ResumeThread(pi.hThread);
}



传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回