目录
一、相关技术介绍和实现原理
二、程序一实现
1. MFC实现一个CreakMe
2. SMC加密技术
3. SMC外部加密程序
4. 花指令
5. 用户名一机一码实现
6. 序列号加密算法
7. 隐藏GetProcAddress函数
8. VMProtectSDK 保护
9. 反调试实现(代码和注释,原理在第一部分)
10. KeyGen
三、程序二实现
1. 基于花指令或SMC技术,实现程序的静态反汇编逆向分析保护
2. 基于反动态调试技术,实现程序的反动态调试保护,要求实现多重反动态调试保护技术
3. 基于序列号保护技术,实现程序的软件版权保护。要求序列号实现和用户名相关并 一机一码,不能使用硬编码序列号。
四、功能测试
1. 程序正常执行流程
2. 简单逆向程序
五、总结
六、附录
proc main:
............
IF .运行条件满足
CALL DecryptProc (Address of MyProc);对某个函数代码解密
........
CALL MyProc ;调用这个函数
........
CALL EncryptProc (Address of MyProc);再对代码进行加密,防止程序被Dump
......
end main
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
#pragma code_seg(".JIANG")
void fun()
{
MessageBox(NULL, TEXT("wrong"), TEXT("错误"), MB_ICONINFORMATION);
}
string Fun1(string userkey, string cpu) //处理之后的用户名,和CPU型号 处理序列号函数
{
string name = "kihnhhkiilh"; //20171120051
char a[50];
char CPU[50];
strcpy_s(CPU, cpu.c_str());
for (int i = 0; i < name.length(); i++)
{
char k = name[i] ^ 'Y';
a[i] = CPU[hex2int(k)];
}
for (int i = 0; i < name.length(); i++)
{
char k = name[i] ^ 'Y';
string s(1, a[i]);
userkey.insert(hex2int(k), s);
}
return userkey;
}
#pragma code_seg()
#pragma comment(linker, "/SECTION:.JIANG,ERW")
void SMC_De(char* pBuf, char* key) //SMC解密函数
{
const char* szSecName = ".JIANG";
short nSec;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_SECTION_HEADER pSec;
pDosHeader = (PIMAGE_DOS_HEADER)pBuf;
pNtHeader = (PIMAGE_NT_HEADERS)& pBuf[pDosHeader->e_lfanew];
nSec = pNtHeader->FileHeader.NumberOfSections;
pSec = (PIMAGE_SECTION_HEADER)& pBuf[sizeof(IMAGE_NT_HEADERS) + pDosHeader->e_lfanew];
for (int i = 0; i < nSec; i++)
{
if (strcmp((char*)& pSec->Name, szSecName) == 0)
{
int pack_size;
char* packStart;
pack_size = pSec->SizeOfRawData;
packStart = &pBuf[pSec->VirtualAddress];
xorPlus(packStart, pack_size, key, strlen(key));
return;
}
pSec++;
}
}
void xorPlus(char* soure, int dLen, char* Key, int Klen) //异或之后再移位
{
for (int i = 0; i < dLen;)
{
for (int j = 0; (j < Klen) && (i < dLen); j++, i++)
{
soure[i] = soure[i] ^ Key[j];
soure[i] = ~soure[i];
}
}
for (int i = 0; i < dLen; i++)
{
char m = soure[i];
soure[i] = soure[dLen - i - 1];
soure[dLen - i - 1] = m;
}
}
string KeyBuffer = "86y6+4y ,787y
70/<+*0- y,4kihnhhkiilh";
for (int i = 0; i <KeyBuffer.length(); i++)
{
KeyBuffer[i] = KeyBuffer[i] ^ 'Y';
}
//取得文件路径部分
TCHAR szFilePath[MAX_PATH];
OPENFILENAME ofn = { 0 };
memset(szFilePath, 0, MAX_PATH);
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.hInstance = GetModuleHandle(NULL);
ofn.nMaxFile = MAX_PATH;
ofn.lpstrInitialDir = ".";
ofn.lpstrFile = szFilePath;
ofn.lpstrTitle = "选择PE文件";
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrFilter = "(*.*)\0*.exe;*.dll\0";
GetOpenFileName(&ofn);
if (szFilePath == NULL)
{
MessageBox(NULL, "打开文件错误", NULL, NULL);
//return 0;
}
//创建文件句柄
HANDLE hFile;
char KeyBuffer[MAX_PATH] = "ao Form yunNan University Num:20171120051";
hFile = CreateFile(szFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, TEXT("打开文件失败"), NULL, NULL);
return;
}
void xorPlus(char* soure, int dLen, char* Key, int Klen)
{
for (int i = 0; i < dLen;)
{
for (int j = 0; (j < Klen) && (i < dLen); j++, i++)
{
soure[i] = soure[i] ^ Key[j];
soure[i] = ~soure[i];
}
}
for (int i = 0; i < dLen; i++)
{
char m = soure[i];
soure[i] = soure[dLen - i - 1];
soure[dLen - i - 1] = m;
}
}
void SMC(HANDLE hFile, char* key)
{
// SMC 加密XX区段
HANDLE hMap;
const char* szSecName = ".JIANG";
char* pBuf;
int size;
short nSec;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_SECTION_HEADER pSec;
size = GetFileSize(hFile, 0);
hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, size, NULL);
if (hMap == INVALID_HANDLE_VALUE)
{
_viewf:
MessageBox(NULL, TEXT("映射失败"), NULL, NULL);
return;
}
pBuf = (char*)MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, size);
if (!pBuf) goto _viewf;
pDosHeader = (PIMAGE_DOS_HEADER)pBuf;
pNtHeader = (PIMAGE_NT_HEADERS)& pBuf[pDosHeader->e_lfanew];
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
MessageBox(NULL, TEXT("不是有效的win32 可执行文件"), NULL, NULL);
goto _clean;
}
nSec = pNtHeader->FileHeader.NumberOfSections;
pSec = (PIMAGE_SECTION_HEADER)& pBuf[sizeof(IMAGE_NT_HEADERS) + pDosHeader->e_lfanew];
for (int i = 0; i < nSec; i++)
{
if (strcmp((char*)& pSec->Name, szSecName) == 0)
{
int pack_size;
char* packStart;
pack_size = pSec->SizeOfRawData;
packStart = &pBuf[pSec->PointerToRawData];
xorPlus(packStart, pack_size, key, strlen(key));
MessageBox(NULL, TEXT("加密成功"), NULL, NULL);
goto _clean;
}
pSec++;
}
MessageBox(NULL, TEXT("未找到JIANG区段,加密失败"), NULL, NULL);
_clean:
UnmapViewOfFile(pBuf);
CloseHandle(hMap);
return;
}
#define FUN0 lo0 //垃圾函数
#define FUN1 lo1
#define FUN2 lo2
#define FUN3 lo3
static inline int FUN0(void)
{
volatile int i = 138, j = 1949;
if ((i++) % 2 > 0) j *= i;
if (j < 0) i *= 2;
else return 0;
i = 1;
while (i++ < 2) { j /= i; j++; i++; }
return i;
}
static inline int FUN1(void)
{
volatile int i = 21, j = 75;
if ((i--) % 3 > 0) j *= i;
if (j > 1) i *= 3;
else return 1;
i = 1;
while (i++ < 3) { j /= i; j--; i++; }
return j;
}
static inline int FUN2(void)
{
volatile int i = 56, j = 17;
if ((i--) % 5 > 0) j *= i;
if (j > 2) i *= 5;
else return 0;
i = 1;
while (i++ < 5) { j *= i; j += 3; i += 3; }
return i;
}
static inline int FUN3(void)
{
volatile int i = 1909, j = 131;
if ((i--) % 7 > 0) j *= i;
if (j > 3) i *= 7;
else return 1;
i = 1;
while (i++ < 7) { j /= i; j -= 5; i += 5; }
return i;
}
#define _FLOWER_FUN_0 {if(FUN2())FUN1();if(FUN0()) FUN3();if(FUN1()) FUN2();if(FUN3()) FUN1(); \
if(FUN1())FUN0();if(FUN2()) FUN3();if(FUN3()) FUN1();if(FUN1()) FUN0();}
#define _FLOWER_FUN_1 {if(FUN3())FUN1();if(FUN1()) FUN2();if(FUN2()) FUN0();if(FUN0()) FUN1(); \
if(FUN2())FUN1();if(FUN0()) FUN3();if(FUN1()) FUN2();if(FUN3()) FUN1();}
string GetManID()//获取制造商信息
{
char ID[25];//存储制造商信息
memset(ID, 0, sizeof(ID));//先清空数组 ID
ExeCPUID(0);//初始化
memcpy(ID + 0, &debx, 4);//制造商信息前四个字符复制到数组
memcpy(ID + 4, &dedx, 4);//中间四个
memcpy(ID + 8, &decx, 4);//最后四个
//如果返回 char * ,会出现乱码;故返回 string 值
return string(ID);
}
void ExeCPUID(DWORD veax)//初始化CPU
{
__asm
{
mov eax, veax
cpuid
mov deax, eax
mov debx, ebx
mov decx, ecx
mov dedx, edx
}
}
processId = GetCurrentProcessId(); //进程pid
string username(string CPU, DWORD pid) //异或拼接
{
string cur_str = to_string(long long(pid));
int j = 0;
for (int i=0; i < CPU.length(); i++)
{
CPU[i] = CPU[i] ^cur_str[j];
j++;
if (j == cur_str.length() - 1)
j = 0;
}
return CPU;
}
string Fun1(string userkey, string cpu) //处理之后的用户名,和CPU型号 处理序列号函数
{
string name = "kihnhhkiilh"; //20171120051
char a[50];
char CPU[50];
strcpy_s(CPU, cpu.c_str());
for (int i = 0; i < name.length(); i++)
{
char k = name[i] ^ 'Y';
a[i] = CPU[hex2int(k)];
}
for (int i = 0; i < name.length(); i++)
{
char k = name[i] ^ 'Y';
string s(1, a[i]);
userkey.insert(hex2int(k), s);
}
return userkey;
}
DWORD MyGetProcAddress(
HMODULE hModule, // DLL的句柄,就是模板映射的基地址
LPCSTR lpProcName // 需要查找的函数名字或者序号
)
{
int i = 0;
char* pRet = NULL;
PIMAGE_DOS_HEADER pImageDosHeader = NULL;
PIMAGE_NT_HEADERS pImageNtHeader = NULL;
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;
pImageDosHeader = (PIMAGE_DOS_HEADER)hModule;
pImageNtHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + pImageDosHeader->e_lfanew);
pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModule + pImageNtHeader->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD dwExportRVA = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD dwExportSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
DWORD* pAddressOfFunction = (DWORD*)(pImageExportDirectory->AddressOfFunctions + (DWORD)hModule);
DWORD* pAddressOfNames = (DWORD*)(pImageExportDirectory->AddressOfNames + (DWORD)hModule);
DWORD dwNumberOfNames = (DWORD)(pImageExportDirectory->NumberOfNames);
DWORD dwBase = (DWORD)(pImageExportDirectory->Base);
WORD* pAddressOfNameOrdinals = (WORD*)(pImageExportDirectory->AddressOfNameOrdinals + (DWORD)hModule);
//这个是查一下是按照什么方式(函数名称or函数序号)来查函数地址的
DWORD dwName = (DWORD)lpProcName;
if ((dwName & 0xFFFF0000) == 0)
{
goto xuhao;
}
for (i = 0; i < (int)dwNumberOfNames; i++)
{
char* strFunction = (char*)(pAddressOfNames[i] + (DWORD)hModule);
if (strcmp(strFunction, (char*)lpProcName) == 0)
{
pRet = (char*)(pAddressOfFunction[pAddressOfNameOrdinals[i]] + (DWORD)hModule);
goto _exit11;
}
}
//这个是通过以序号的方式来查函数地址的
xuhao:
if (dwName < dwBase || dwName > dwBase + pImageExportDirectory->NumberOfFunctions - 1)
{
return 0;
}
pRet = (char*)(pAddressOfFunction[dwName - dwBase] + (DWORD)hModule);
_exit11:
//判断得到的地址有没有越界
if ((DWORD)pRet<dwExportRVA + (DWORD)hModule || (DWORD)pRet > dwExportRVA + (DWORD)hModule + dwExportSize)
{
return (DWORD)pRet;
}
char pTempDll[100] = { 0 };
char pTempFuction[100] = { 0 };
strcpy(pTempDll, pRet);
char* p = strchr(pTempDll, '.');
if (!p)
{
return (DWORD)pRet;
}
*p = 0;
strcpy(pTempFuction, p + 1);
strcat(pTempDll, ".dll");
LPWSTR k[100] = { 0 };
TCHAR aaa[31];
MultiByteToWideChar(0, 0, pTempDll , 31, aaa, 62);
HMODULE h = LoadLibrary(aaa);
if (h == NULL)
{
return (DWORD)pRet;
}
return MyGetProcAddress(h, pTempFuction);
}
BOOL Fan1()
{
return IsDebuggerPresent();
}
BOOL Fan2()
{
BOOL ret;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &ret);
return ret;
}
bool PebIsDebugged() //检查PEB BeingDebugged标志位
{
char result = 0;
__asm
{
// 进程的PEB地址放在fs这个寄存器位置上
mov eax, fs: [30h]
// 查询BeingDebugged标志位
mov al, BYTE PTR[eax + 2]
mov result, al
}
return result != 0;
}
bool PebNtGlobalFlags() //检查NtGlobal标志位 NtGlobal标志位
{
int result = 0;
__asm
{
// 进程的PEB
mov eax, fs: [30h]
// 控制堆操作函数的工作方式的标志位
mov eax, [eax + 68h]
// 操作系统会加上这些标志位FLG_HEAP_ENABLE_TAIL_CHECK,
// FLG_HEAP_ENABLE_FREE_CHECK and FLG_HEAP_VALIDATE_PARAMETERS,
// 它们的并集就是x70
and eax, 0x70 //&
mov result, eax
}
return result != 0;
}
bool HeapFlags() //检查堆头信息
{
int result = 0;
__asm
{
// 进程的PEB
mov eax, fs: [30h]
mov eax, [eax + 18h]
mov eax, [eax + 44h] //win7 win10
mov result, eax
}
return result != 0;
}
typedef NTSTATUS(WINAPI* NtQueryInformationProcessPtr)( //NtQueryInformationProcess函数检查端口返回值
HANDLE processHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID processInformation,
ULONG processInformationLength,
PULONG returnLength);
int NtQueryInformationProcess()
{
int debugPort = 0;
HMODULE hModule = LoadLibrary(TEXT("Ntdll.dll ")); //调用Ntdll链接库
NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)MyGetProcAddress(hModule, "NtQueryInformationProcess");
if (NtQueryInformationProcess(GetCurrentProcess(), (PROCESSINFOCLASS)7, &debugPort, sizeof(debugPort), NULL))
printf("[ERROR NtQueryInformationProcessApproach] NtQueryInformationProcess failed\n");
else
return debugPort ==-1;
return 0; //返回端口是0就不在调试
}
typedef NTSTATUS(*NtSetInformationThreadPtr)(HANDLE threadHandle, // NtSetInformationThread方法
THREADINFOCLASS threadInformationClass,
PVOID threadInformation,
ULONG threadInformationLength);
void NtSetInformationThread() //你可以在当前线程里调用NtSetInformationThread,调用这个函数时,如果在第二个参数里指定0x11这个值(意思是ThreadHideFromDebugger)
{
HMODULE hModule = LoadLibrary(TEXT("Ntdll.dll"));
NtSetInformationThreadPtr NtSetInformationThread = (NtSetInformationThreadPtr)MyGetProcAddress(hModule, "NtSetInformationThread");
NtSetInformationThread(GetCurrentThread(), (THREADINFOCLASS)0x11, 0, 0);
}
LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* pei)
{
//MessageBox(NULL, TEXT("反调试8 经过异常处理函数"), TEXT("信息"), MB_ICONINFORMATION);
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)
pei->ContextRecord->Eax);
// 修改寄存器eip的值
pei->ContextRecord->Eip += 2;
// 告诉操作系统,继续执行进程剩余的指令(指令保存在eip里),而不是关闭进程
return EXCEPTION_CONTINUE_EXECUTION;
}
bool UnhandledExceptionFilterApproach()
{
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
__asm
{
// 将eax清零
xor eax, eax
// 触发一个除零异常
div eax
}
return false;
}
BOOL Fan10() //找窗口
{
if (FindWindowA("OLLYDBG", NULL) != NULL || FindWindowA("WinDbgFrameClass", NULL) != NULL || FindWindowA("QWidget", NULL) != NULL)
{
return TRUE;
}
else
{
return FALSE;
}
}
BOOL Fan11() //前台窗口
{
char fore_window[1024];
GetWindowTextA(GetForegroundWindow(), fore_window, 1023);
if (strstr(fore_window, "WinDbg") != NULL || strstr(fore_window, "x64_dbg") != NULL || strstr(fore_window, "OllyICE") != NULL || strstr(fore_window, "OllyDBG") != NULL || strstr(fore_window, "Immunity") != NULL)
{
return TRUE;
}
else
{
return FALSE;
}
}
BOOL Fan12()
{
DWORD ID;
DWORD ret = 0;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bMore = Process32First(hProcessSnap, &pe32);
while (bMore)
{
if (TCHAR2STRING2(pe32.szExeFile) =="OLLYDBG.EXE" || TCHAR2STRING2(pe32.szExeFile) == "OllYICE.exe" || _stricmp((char*)pe32.szExeFile, "x64_dbg.exe") == 0 || _stricmp((char*)pe32.szExeFile, "windbg.exe") == 0 || _stricmp((char*)pe32.szExeFile, "ImmunityDebugger.exe") == 0)
{
MessageBox(NULL, TEXT("反调试12"), TEXT("信息"), MB_ICONINFORMATION);
return TRUE;
}
bMore = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
return FALSE;
}
BOOL Fan13() //软件断点检测
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS32 pNtHeaders;
PIMAGE_SECTION_HEADER pSectionHeader;
DWORD dwBaseImage = (DWORD)GetModuleHandle(NULL);
pDosHeader = (PIMAGE_DOS_HEADER)dwBaseImage;
pNtHeaders = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(pNtHeaders->Signature) + sizeof(IMAGE_FILE_HEADER) +
(WORD)pNtHeaders->FileHeader.SizeOfOptionalHeader);
DWORD dwAddr = pSectionHeader->VirtualAddress + dwBaseImage;
DWORD dwCodeSize = pSectionHeader->SizeOfRawData;
BOOL Found = FALSE;
__asm
{
cld
mov edi, dwAddr
mov ecx, dwCodeSize
mov al, 0CCH
repne scasb
jnz NotFound
mov Found, 1
NotFound:
}
return Found;
}
BOOL Fun14() //检查四个硬件断点
{
CONTEXT context;
HANDLE hThread = GetCurrentThread();
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(hThread, &context);
if (context.Dr0 != 0 || context.Dr1 != 0 || context.Dr2 != 0 || context.Dr3 != 0)
{
return TRUE; //在调试状态
}
return FALSE;
}
#include<iostream>
using namespace std;
int hex2int(char c)
{
if ((c >= 'A') && (c <= 'Z'))
{
return c - 'A' + 10;
}
else if ((c >= 'a') && (c <= 'z'))
{
return c - 'a' + 10;
}
else if ((c >= '0') && (c <= '9'))
{
return c - '0';
}
}
int main(int argv, char *argc[])
{
string cpu = "GenuineIntel";
string pid(argc[1]);
int j = 0;
for (int i = 0; i < cpu.length(); i++)
{
cpu[i] = cpu[i] ^ pid[j];
j++;
if (j == pid.length() - 1)
j = 0;
}
cout << cpu << endl;
string cpu2 = "GenuineIntel";
string name = "kihnhhkiilh";
char a[50];
char CPU[50];
strcpy_s(CPU, cpu2.c_str());
for (int i = 0; i < name.length(); i++)
{
char k = name[i] ^ 'Y';
a[i] = CPU[hex2int(k)];
}
for (int i = 0; i < name.length(); i++)
{
char k = name[i] ^ 'Y';
string s(1, a[i]);
cpu.insert(hex2int(k), s);
}
cout << cpu << endl;
return 0;
}
看雪ID:菜鸟m号
https://bbs.pediy.com/user-856851.htm
推荐文章++++
* 实战栈溢出漏洞