注册机偷懒写法1、之直接扣代码
注册机偷懒写法2、之直接调用源程序的函数
注册机偷懒写法3、内联Hook让程序自己弹出注册码
注册机偷懒写法4、调试模式下获取
这个方法可能会比较通用,编写个简单调试器,调试源程序,从内存或者寄存器中获取注册码。
#include
#include
#include
#pragma comment(lib, "dbghelp.lib")
#include
using std::vector;
typedef struct _SOFTBREAKEPOINT
{
LPVOID address; //地址
BYTE old_byte; //原始数据
DWORD old_protect; //页面属性
BOOL enbale; //断点是否启用
}SOFTBREAKEPOINT, *PSOFTBREAKEPOINT;
/*
找到关键代码的地址,下断点,让后在从内存中读取
*/
typedef struct _DBG_REG7
{
/*
// 局部断点(L0~3)与全局断点(G0~3)的标记位
*/
unsigned L0 : 1; // 对Dr0保存的地址启用 局部断点
unsigned G0 : 1; // 对Dr0保存的地址启用 全局断点
unsigned L1 : 1; // 对Dr1保存的地址启用 局部断点
unsigned G1 : 1; // 对Dr1保存的地址启用 全局断点
unsigned L2 : 1; // 对Dr2保存的地址启用 局部断点
unsigned G2 : 1; // 对Dr2保存的地址启用 全局断点
unsigned L3 : 1; // 对Dr3保存的地址启用 局部断点
unsigned G3 : 1; // 对Dr3保存的地址启用 全局断点
/*
// 【以弃用】用于降低CPU频率,以方便准确检测断点异常
*/
unsigned LE : 1;
unsigned GE : 1;
/*
// 保留字段
*/
unsigned Reserve1 : 3;
/*
// 保护调试寄存器标志位,如果此位为1,则有指令修改条是寄存器时会触发异常
*/
unsigned GD : 1;
/*
// 保留字段
*/
unsigned Reserve2 : 2;
/*
// 保存Dr0~Dr3地址所指向位置的断点类型(RW0~3)与断点长度(LEN0~3),状态描述如下:
*/
unsigned RW0 : 2; // 设定Dr0指向地址的断点类型
unsigned LEN0 : 2; // 设定Dr0指向地址的断点长度
unsigned RW1 : 2; // 设定Dr1指向地址的断点类型
unsigned LEN1 : 2; // 设定Dr1指向地址的断点长度
unsigned RW2 : 2; // 设定Dr2指向地址的断点类型
unsigned LEN2 : 2; // 设定Dr2指向地址的断点长度
unsigned RW3 : 2; // 设定Dr3指向地址的断点类型
unsigned LEN3 : 2; // 设定Dr3指向地址的断点长度
}DBG_REG7, PDBG_REG7;
LPVOID m_addr; //异常地址
BOOL m_Exit = FALSE; //是否退出
LPVOID m_ImageBase; //基址
DWORD m_tid; //当前线程ID
PROCESS_INFORMATION pi = { 0 };
vectorm_bplist; //软件断点列表
BOOL create_process(const char * path_name);
BOOL create_ActiveProces(DWORD pid);
BOOL loopDebugEvent();
BOOL loopDebugEvent();
DWORD OnExceptionDispatch(EXCEPTION_DEBUG_INFO * dbg_execption);
//DWORD OnException_Sinlge();
DWORD OnException_breakpoint();
//void SetHardRegist(LPVOID addr, DWORD type, DWORD len);
BOOL SetBrekePoint(LPVOID address);
BOOL RecoveBrekePoint(LPVOID address);
BOOL m_systembp = TRUE; //系统断点
int main()
{
create_process("Dope2112.1.exe");
loopDebugEvent();
return 0;
}
//打开方式
BOOL create_process(const char * path_name)
{
STARTUPINFO sf = { sizeof(sf) };
//PROCESS_INFORMATION pi = { 0 };
BOOL bret = CreateProcess(
path_name, //exe路径
NULL, //命令行参数
NULL, //进程安全属性
NULL, //线程安全属性
FALSE, //是否继承句柄
//只调试方式启动,创建控制台
DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE,
NULL, //运行环境变量
NULL, //工作目录
&sf, //启动信息
&pi); //进程信息
//SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
SymInitialize(pi.hProcess, NULL, FALSE);
return bret;
}
//附加
BOOL create_ActiveProces(DWORD pid)
{
return DebugActiveProcess(pid);
}
//3. 循环等待事件
BOOL loopDebugEvent()
{
DEBUG_EVENT m_deevent;
DWORD dbg_continue = DBG_CONTINUE;
//循环等待调试事件
while (!m_Exit)
{
//等待调试事件
WaitForDebugEvent(&m_deevent, -1);
m_tid = m_deevent.dwThreadId;
//分发调试事件
switch (m_deevent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT: //异常信息
dbg_continue = OnExceptionDispatch(&m_deevent.u.Exception);
break;
case CREATE_THREAD_DEBUG_EVENT: //线程被创建
m_deevent.u.CreateThread.lpStartAddress; //线程入口点
break;
case CREATE_PROCESS_DEBUG_EVENT: //进程被创建
{
m_ImageBase = m_deevent.u.CreateProcessInfo.lpBaseOfImage;
}
break;
case EXIT_THREAD_DEBUG_EVENT: //线程退出
break;
case EXIT_PROCESS_DEBUG_EVENT: // 进程退出
m_Exit = TRUE;
break;
case LOAD_DLL_DEBUG_EVENT: //dll加载
break;
case UNLOAD_DLL_DEBUG_EVENT: //dll卸载
break;
case OUTPUT_DEBUG_STRING_EVENT: //调试输出
break;
case RIP_EVENT: //内部错误
break;
}
//回复子系统 ,事件是否处理
ContinueDebugEvent(
m_deevent.dwProcessId, //进程ID
m_deevent.dwThreadId, //线程ID
dbg_continue); //事件是否处理
}
return TRUE;
}
DWORD OnExceptionDispatch(EXCEPTION_DEBUG_INFO * dbg_execption)
{
DWORD dbg_continue = DBG_CONTINUE;
//异常代码
DWORD Code = dbg_execption->ExceptionRecord.ExceptionCode;
//异常地址
m_addr = dbg_execption->ExceptionRecord.ExceptionAddress;
//检测异常类型
switch (Code)
{
case EXCEPTION_BREAKPOINT: //软件断点异常
dbg_continue = OnException_breakpoint();
break;
case EXCEPTION_ACCESS_VIOLATION: //访问异常
break;
case EXCEPTION_SINGLE_STEP: //硬件断点-单步断点
/*dbg_continue = OnException_Sinlge();*/
break;
}
return dbg_continue;
}
//硬件点
//DWORD OnException_Sinlge()
//{
// HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, m_tid);
// CONTEXT context = { CONTEXT_ALL };
// GetThreadContext(ht, &context);
// CloseHandle(ht);
// DWORD temp = *(DWORD *)(context.Ebp - 18);
// char str[20] = { 0 };
// ReadProcessMemory(pi.hProcess, (LPCVOID)temp, str, sizeof(str), NULL);
// printf(str);
// getchar();
// return DBG_CONTINUE;
//}
// 软件异常
DWORD OnException_breakpoint()
{
/*
00421CFE | E8 71 36 FE FF | call | ???
00421D03 | 8D 55 E4 | lea edx,dword ptr ss:[ebp-1C] | [ebp-1C]:"46"
00421D06 | 33 C0 | xor eax,eax | [ebp-1c]临时变量
00421D08 | 8A C3 | mov al,bl |
00421D0A | E8 65 36 FE FF | call | ???
00421D0F | FF 75 E4 | push dword ptr ss:[ebp-1C] | [ebp-1C]:"46"
00421D12 | 68 D8 1D 42 00 | push dope2112.1.421DD8 | 421DD8:L"-"
00421D17 | FF 75 F0 | push dword ptr ss:[ebp-10] | [ebp-10]:"114420"
00421D1A | 8D 45 F4 | lea eax,dword ptr ss:[ebp-C] | [ebp-C]:"46-114420"
00421D1D | BA 03 00 00 00 | mov edx,3 | [ebp-c]存储姓名计算出的密码
00421D22 | E8 FD 16 FE FF | call | 1.sub_403424)
00421D27 | 8D 55 E8 | lea edx,dword ptr ss:[ebp-18] | [ebp-18]:"123456"
*/
//在程序运行到00421D27时[ebp-C]:"46-133490"中保存着注册码,hook 00421D27
//计算新的位置
LPVOID ptemp = (LPVOID)((DWORD)m_ImageBase + 0x21D27);
//检测系统断点
if (m_systembp)
{
//在00421D27设置执行断点
SetBrekePoint(ptemp);
m_systembp = FALSE;
}
else
{
RecoveBrekePoint(m_addr);
if (ptemp == m_addr)
{
HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, m_tid);
CONTEXT context = { CONTEXT_ALL };
GetThreadContext(ht, &context);
CloseHandle(ht);
DWORD temp = 0;
ReadProcessMemory(pi.hProcess, (LPCVOID)(context.Ebp - 0xc), &temp, sizeof(temp), NULL);
char str[20] = { 0 };
ReadProcessMemory(pi.hProcess, (LPCVOID)temp, str, sizeof(str), NULL);
printf(str);
getchar();
}
}
return DBG_CONTINUE;
}
//硬件断点
//void SetHardRegist(LPVOID addr, DWORD type, DWORD len)
//{
// HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, m_tid);
// CONTEXT context = { CONTEXT_ALL };
// //2.获取线程上线文
// GetThreadContext(ht, &context);
// auto Pctx = &context;
// DBG_REG7* pDr7;
// //获取Dr7字段
// pDr7 = (DBG_REG7*)&Pctx->Dr7;
// //检测是Dr0是否空,可以写入
// if (Pctx->Dr0 == 0)
// {
// //写入地址
// Pctx->Dr0 = (DWORD)addr;
// //写入局部断点有效
// pDr7->L0 = 1;
// //断点类型,type: 0 执行,1写入 3读写
// pDr7->RW0 = type;
// //长度 len: 0一个字节,1两个字节 3四个字节
// pDr7->LEN0 = len;
// }
// else if (Pctx->Dr1 == 0)
// {
// Pctx->Dr1 = (DWORD)addr;
// pDr7->L1 = 1;
// pDr7->RW1 = type;
// pDr7->LEN1 = len;
// }
// else if (Pctx->Dr2 == 0)
// {
// Pctx->Dr2 = (DWORD)addr;
// pDr7->L2 = 1;
// pDr7->RW2 = type;
// pDr7->LEN2 = len;
// }
// else if (Pctx->Dr3 == 0)
// {
// Pctx->Dr3 = (DWORD)addr;
// pDr7->L3 = 1;
// pDr7->RW3 = type;
// pDr7->LEN3 = len;
// }
// if (!SetThreadContext(ht, &context))
// printf("设置硬件断点失败!");
// CloseHandle(ht);
//}
//设置软件断点
BOOL SetBrekePoint(LPVOID address)
{
SOFTBREAKEPOINT bp;
bp.address = address;
bp.enbale = TRUE;
//1. 打开进程
HANDLE hps = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
//2. 修改页面属性
VirtualProtectEx(hps,
address,
1,
PAGE_EXECUTE_READWRITE,
&bp.old_protect);
DWORD dwSize;
//3. 读取原始数据
ReadProcessMemory(hps, address, &bp.old_byte, 1, &dwSize);
//4. 写入cc断点
WriteProcessMemory(hps, address, "\xcc", 1, &dwSize);
//5. 保存断点信息
m_bplist.push_back(bp);
//6. 恢复页面属性
VirtualProtectEx(hps,
address,
1,
bp.old_protect,
&dwSize);
//7. 关闭句柄
CloseHandle(hps);
return TRUE;
}
// 恢复软件断点
BOOL RecoveBrekePoint(LPVOID address)
{
for (int i = 0; i < m_bplist.size(); i++)
{
//如果是断点列表中的异常
if (m_bplist[i].address == address)
{
//1. 打开进程
HANDLE hps =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
//2. 修改页面属性
DWORD dwProtect;
VirtualProtectEx(hps,
address,
1,
PAGE_EXECUTE_READWRITE,
&dwProtect);
DWORD dwSize;
//4. 写入原始数据
WriteProcessMemory(
hps,
address,
&m_bplist[i].old_byte,
1, &dwSize);
//6. 恢复页面属性
VirtualProtectEx(hps,
address,
1,
m_bplist[i].old_protect,
&dwSize);
//7. 关闭句柄
CloseHandle(hps);
return TRUE;
}
}
return FALSE;
}
源码
https://download.csdn.net/download/u012332009/11122063
源程序的分析请看
[反汇编练习] 160个CrackMe之044
(出处: 吾爱破解论坛)