zoukankan      html  css  js  c++  java
  • C/C++ 对代码节的动态加解密

    加壳的原理就是加密或者压缩程序中的已有资源,然后当程序执行后外壳将模拟PE加载器对EXE中的区块进行动态装入,下面我们来自己实现一个简单的区块加解密程序,来让大家学习了解一下壳的基本运作原理。

    本次使用的工具,依旧是上次编写的PETools: https://www.cnblogs.com/LyShark/p/12960816.html

    加密第一个节表:

    #include <stdio.h>
    #include <Windows.h>
    #include <ImageHlp.h>
    #pragma comment(lib,"Imagehlp.lib")
    
    void EncrySection(LPSTR szFileName)
    {
    	HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
    		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
    	HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
    
    	PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
    	PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
    	PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
    	PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
    
    	printf("节表数量: %d 
    ", FileHdr->NumberOfSections);
    	printf("节虚拟地址: %x 
    ", pSection->Misc.VirtualSize);
    	printf("读入FOA基地址: %x 
    ", pSection->PointerToRawData);
    	printf("读入节表长度: %x 
    ", pSection->SizeOfRawData);
    
    	DWORD dwRead = 0;
    	PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	memset(pByte, 0, pSection->SizeOfRawData);
    	ReadFile(hFile, pByte, pSection->SizeOfRawData, &dwRead, NULL);
    
    	for (int x = 0; x < pSection->SizeOfRawData; x++)
    		pByte[x] ^= 0x10;
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
    
    	UnmapViewOfFile(lpBase);
    }
    
    int main(int argc, char * argv[])
    {
    	EncrySection("c://win32.exe");
    	system("pause");
    	return 0;
    }
    

    当需要打印第二个节只需要递增指针.

    void EncrySection(LPSTR szFileName)
    {
    	HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
    		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
    	HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
    
    	PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
    	PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
    	PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
    	PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
    
    	printf("节表数量: %d 
    ", FileHdr->NumberOfSections);
    	printf("节虚拟地址: %x 
    ", pSection->Misc.VirtualSize);
    	printf("读入FOA基地址: %x 
    ", pSection->PointerToRawData);
    	printf("读入节表长度: %x 
    ", pSection->SizeOfRawData);
    
    	DWORD dwRead = 0;
    	PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	memset(pByte, 0, pSection->SizeOfRawData);
    	
    	// 逐字节读入
    	for (int x = 0; x < pSection->PointerToRawData; x++)
    	{
    		ReadFile(hFile, &pByte[x], 1, &dwRead, NULL);
    	}
    
    	for (int x = 0; x < pSection->SizeOfRawData; x++)
    		pByte[x] ^= 0x10;
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
    
    	pSection++;
    	printf("节虚拟地址: %x 
    ", pSection->Misc.VirtualSize);
    	printf("读入FOA基地址: %x 
    ", pSection->PointerToRawData);
    	printf("读入节表长度: %x 
    ", pSection->SizeOfRawData);
    	UnmapViewOfFile(lpBase);
    }
    

    循环加密所有的节,可能会出现问题

    #include <stdio.h>
    #include <Windows.h>
    #include <ImageHlp.h>
    #pragma comment(lib,"Imagehlp.lib")
    
    void EncrySection(LPSTR szFileName,DWORD Key)
    {
    	HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
    		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
    	HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
    
    	PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
    	PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
    	PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
    	PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
    	printf("[-] 加密节表数量: %d 
    ", FileHdr->NumberOfSections);
    
    	for (int x = 0; x < FileHdr->NumberOfSections; x++)
    	{
    		printf("[-] 节虚拟地址: 0x%08X 虚拟大小: 0x%08X
    ", pSection->VirtualAddress,pSection->Misc.VirtualSize);
    		printf("[-] 读入FOA基地址: 0x%08X 节表长度: 0x%08X 
    
    ", pSection->PointerToRawData,pSection->SizeOfRawData);
    
    		DWORD dwRead = 0;
    		PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
    
    		SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    		memset(pByte, 0, pSection->SizeOfRawData);
    		ReadFile(hFile, pByte, pSection->SizeOfRawData, &dwRead, NULL);
    
    		for (int x = 0; x < pSection->SizeOfRawData; x++)
    		{
    			pByte[x] ^= Key;
    		}
    
    		SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    		WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
    
    		free(pByte);
    		pSection = pSection + 1;
    	}
    	UnmapViewOfFile(lpBase);
    }
    
    int main(int argc, char * argv[])
    {
    	EncrySection("c://win32.exe",0x10);
    	system("pause");
    	return 0;
    }
    

    添加壳代码

    #include <stdio.h>
    #include <Windows.h>
    #include <ImageHlp.h>
    #pragma comment(lib,"Imagehlp.lib")
    
    void EncrySection(LPSTR szFileName, DWORD Key)
    {
    	HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
    		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
    	HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
    
    	PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
    	PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
    	PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
    	PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
    	printf("[-] 节虚拟地址: 0x%08X 虚拟大小: 0x%08X
    ", pSection->VirtualAddress, pSection->Misc.VirtualSize);
    	printf("[-] 读入FOA基地址: 0x%08X 节表长度: 0x%08X 
    ", pSection->PointerToRawData, pSection->SizeOfRawData);
    	printf("[*] 已对 %s 节 --> XOR加密/解密 --> XOR密钥: %d 
    
    ", pSection->Name, Key);
    
    	DWORD dwRead = 0;
    	PBYTE pByte = (PBYTE)malloc(pSection->SizeOfRawData);
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	memset(pByte, 0, pSection->SizeOfRawData);
    	ReadFile(hFile, pByte, pSection->SizeOfRawData, &dwRead, NULL);
    
    	for (int x = 0; x < pSection->SizeOfRawData; x++)
    	{
    		pByte[x] ^= Key;
    	}
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	WriteFile(hFile, pByte, pSection->SizeOfRawData, 0, FILE_BEGIN);
    	pSection->Characteristics = 0xE0000020;
    
    	free(pByte);
    	FlushViewOfFile(lpBase, 0);
    	UnmapViewOfFile(lpBase);
    }
    
    void DecodeCode(LPSTR szFileName)
    {
    	// 第一步修正程序OEP位置,修正为最后一个节的地址
    	HANDLE hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
    		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
    	HANDLE lpBase = MapViewOfFile(hMap, FILE_MAP_READ | FILE_SHARE_WRITE, 0, 0, 0);
    
    	PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER)lpBase;
    	PIMAGE_NT_HEADERS NtHdr = (PIMAGE_NT_HEADERS)((DWORD)lpBase + DosHdr->e_lfanew);
    
    	DWORD ImageBase = NtHdr->OptionalHeader.ImageBase;
    	DWORD BaseRVA = NtHdr->OptionalHeader.AddressOfEntryPoint;
    	printf("Base RVA %x 
    ", BaseRVA);
    
    
    	PIMAGE_FILE_HEADER FileHdr = &NtHdr->FileHeader;
    	PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(NtHdr);
    
    
    	// 首先得到最后一个节的指针,然后找到里面的虚拟偏移值,填入到程序OEP位置即可。
    	DWORD SectionNum = FileHdr->NumberOfSections;
    	char Code[] =
    	{
    		"x60"
    		"xb8x00x00x00x00"
    		"x80x30x88"
    		"x40"
    		"x3dxffx4fx40x00"
    		"x75xf5"
    		"x61"
    		"xb8x00x00x00x00"
    		"xffxe0"
    	};
    	DWORD dwWrite = 0;
    	printf("%x 
    ", ImageBase + pSection->VirtualAddress);
    	*(DWORD *)&Code[2] = ImageBase + pSection->VirtualAddress;
    	*(DWORD *)&Code[11] = ImageBase + pSection->VirtualAddress + pSection->Misc.VirtualSize;
    	*(DWORD *)&Code[19] = ImageBase + BaseRVA;
    	pSection = pSection + (SectionNum - 1);
    	printf("得到最后一个节的实际地址: %x 
    ", pSection->PointerToRawData);
    
    	SetFilePointer(hFile, pSection->PointerToRawData, 0, FILE_BEGIN);
    	WriteFile(hFile, (LPVOID)Code, sizeof(Code), &dwWrite, NULL);
    	FlushViewOfFile(lpBase, 0);
    	UnmapViewOfFile(lpBase);
    }
    

    加壳的首要目标是要创建一个具有可写属性的新节

    我们使用PESection对win32.exe加一个.hack节,然后大小为2048

    加入后再次使用PETools工具检查,发现已经添加成功了。

    下一步就是将.text节进行加密了,这里为了简单我使用的是异或加密,如下是加密前的机器码。

    使用我们编写的工具进行加密,传入两个参数,一个是文件,一个则是加密密钥

    加密有区段会变成如下样子。

    接着使用 addpack 传入一个参数,写入解密代码。

    电脑管家可能会拦截,请将其取出来。

    我们X64dbg载入看看,程序默认停在了,我们的壳的位置,。

    运行后对.text节进行动态解密,然后一个jmp跳转到程序的OEP位置即可,这也就是壳的基本原理。

  • 相关阅读:
    在小气的神的Blog上看到的一段Video
    一个在.net下进行用户模拟的类
    PDC每日视频
    今天才知有一个CollectionBase类,惭愧
    “EditandContinue”特性
    Codeforces Round #597 (Div. 2) A. Good ol' Numbers Coloring
    单据号生成
    JAR包
    框架之间传值
    Eclipse3.4发布 新特性展示
  • 原文地址:https://www.cnblogs.com/LyShark/p/13760497.html
Copyright © 2011-2022 走看看