【文章标题】: 剑走偏锋姊妹篇--模拟注册获取注册码
【文章作者】: xuecrack
【软件名称】: GIF Movie Gear V4.2汉化版
【下载地址】: 自己搜索下载
【使用工具】: WinHex, Spy,VC6.0中文版
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
首先声明一下:本文没有高深的技术,纯粹一些总结,高手可一笑飞过。另作者水平有限,错误难免,若各位大侠不吝赐教
则幸甚乐甚!
上次写了一篇文章《剑走偏锋,另辟蹊径获取加密信息》( http://bbs.pediy.com/showthread.php?t=97156)讲从内存中
获取闪讯用户用户名和密码信息的,写的不甚详细。今天这篇文章也是讲从内存中获取信息的,不过是在一系列的模拟手工
操作之后。
【本文思路】
模拟一系列的手工操作,然后从软件内存中获取我们所要的信息。当反汇编发现算法流程很繁复甚至一时半会无法分析出的
时候,抑或想偷懒^_^也可以参考这种方法。
【本文所提方法适用条件】
1、通过一系列操作之后,所需获取的信息某一时机以明文方式出现在软件内存中
2、所需获取的信息有一定规则,可识别
GIF Movie Gear V4.2汉化版正符合以上条件。GIF Movie Gear V4.2内存截图如下:红色的是注册码,蓝色的是用户名
【通常注册共享软件的方法】
运行软件,点击“注册”或“激活”菜单,在注册窗口填写注册信息,确认,软件对输入的信息进行计算,符合一定的条件
则注册成功,否则注册失败。
今天拿来开刀的是一个gif图片制作软件“GIF Movie Gear”,这个软件的算法分析文章网上很多,本文不分析算法,只是
模拟其注册的每一个过程,然后在内存中窃取注册信息。
【GIF Movie Gear的手工注册流程】
1、双击运行GIF Movie Gear的可执行文件movgear.exe,弹出程序主窗口。
2、点击菜单“帮助”-“注册”弹出注册窗口。
3、填写用户名,注册码后单击“确定”按钮。
4、软件计算,或注册成功或注册失败,弹出消息框提示。
过程截图如下

【我的想法】:用模拟完成以上步骤,只要输入用户名,就能获取到对应注册码。略去细节,大致流程:
A、用ShellExecute执行movgear.exe。
B、用FindWindow 获取主窗口句柄,找到“注册”菜单标识,给其投递 WM_COMMAND 消息,模拟点击菜单,弹出注册窗口。
C、通过 GetWindow 函数得到注册窗口的句柄。
获取注册窗口“用户名”文本框句柄,给其发送 WM_SETTEXT 消息,模拟填写用户名。
获取注册窗口“确定”按钮句柄,发送 BM_CLICK 消息,模拟点击“确定”按钮。
这里要注意的是,这软件只填写用户名就会调用注册码计算代码,不管所填注册码是否为空,所以上面不需要模拟填写
注册假码。
D、打开GIF Movie Gear程序进程,在一定内存地址范围内搜索注册码,并获取之,然后用 TerminateProcess 终止GIF
Movie Gear进程,并输出有效注册码。
上面ABCD四个步骤对应前面的1234流程。
我写了个小程序,就像一个黑匣子,对内输入用户名,对外显示正确的注册码。程序运行界面如下:
细节请参考我写的代码,注释很详细,VC6.0平台,Win Xp Sp3下编译通过。
/****************************************************************
程序作用: 自动获取 GIF Movie Gear 注册码
程序原理:
程序作者: wyART QQ:243261920
代码日期: 2009-09-022
修改日期: 2009-09-023
****************************************************************/
#include<iostream>
#include<windows.h>
using namespace std;
int main(int argc, char* argv[])
{
DWORD pId,dwRdAddr;
BYTE RdData,RdData1,RdData2;
BYTE UsrKey[40];
char userName[100];
char st[100];
//改变控制台标题,外观
system("title GIF Movie Gear KeYgEn");
system("color 0a");
//执行movgear.exe 程序
ShellExecute(NULL,"open","movgear.exe",NULL,NULL,SW_HIDE);
//等待程序初始化完成
Sleep(1000);
//获取GIF Movie Gear主窗口句柄
HWND hWnd=FindWindow("GIF Movie Gear","GIF Movie Gear");
if (0==hWnd)
{
cout<<"Get GIF Movie Gear Window Handle Error ! "<<endl;
return 0;
}
//投递消息,模拟鼠标点击“帮助”-->“注册”菜单,40036可由测试得到
PostMessage(hWnd,WM_COMMAND,40036,NULL);
//为注册窗口生成等待时间
Sleep(200);
//获取注册窗口句柄,方法用SPY查看
HWND HwndSubWnd=GetWindow(hWnd,GW_HWNDPREV);
HwndSubWnd=GetWindow(HwndSubWnd,GW_HWNDPREV);
if (0==HwndSubWnd)
{
cout<<"Get Reg Window Handle Error!"<<endl;
return 0;
}
//为不影响控制台程序操作,隐藏注册窗口
ShowWindow(HwndSubWnd, SW_HIDE);
//使控制台程序重新获得焦点
HWND hConsole=FindWindow(NULL,"GIF Movie Gear KeYgEn");
if(hConsole)
SetForegroundWindow(hConsole);
//获取注册窗口“用户名”文本框句柄
HWND HwndEdit=FindWindowEx(HwndSubWnd,NULL,"Edit",NULL);
if (0==HwndEdit)
{
cout<<"Get RegWindow Edit Control Handle Error!"<<endl;
return 0;
}
cout<<"Please Input UserName: ";
cin>>userName;
//发送消息,设置注册窗口“用户名”文本框文字
SendMessage(HwndEdit,WM_SETTEXT,0,(LPARAM)(LPCTSTR)(userName));
//获取注册窗口“确定”按钮句柄
HWND HwndCmdOK=FindWindowEx(HwndSubWnd,NULL,"Button","确定");
if (0==HwndCmdOK)
{
cout<<"Get RegWindow Command OK's Handle Error!"<<endl;
return 0;
}
//向注册窗口“确定”按钮投递单击消息
PostMessage(HwndCmdOK,BM_CLICK,0,0);
//获取主窗口线程ID
DWORD threadID=GetWindowThreadProcessId(hWnd,&pId);
//打开主窗口进程,获取进程句柄
HANDLE hPro= OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE ,FALSE,pId);
if(NULL == hPro)
{
cout<<"Can't Open GIF Movie Gear Memory!"<<endl;
return 0;
}
//在范围13a000h~140000h内查找闪讯用户信息,该范围由经验而得
//注册码形式 “FSXPQN-DTHKSP-Z8YT2T-2ARCFK”
//识别注册码的简单方法,读取到第一个“-”出现的位置,位置加7仍为“-”,位置加14仍然是“-”,则可以断定是注册码
dwRdAddr=0x13a000;
while (dwRdAddr<0x140001)
{
ReadProcessMemory(hPro,(LPVOID)dwRdAddr,&RdData,1,NULL);
if (RdData==45) //"-"
{
ReadProcessMemory(hPro,(LPVOID)(dwRdAddr+7),&RdData1,1,NULL);
ReadProcessMemory(hPro,(LPVOID)(dwRdAddr+14),&RdData2,1,NULL);
if (RdData1==45 && RdData2==45 ) //"-"
break;
}
dwRdAddr++;
}
//读取信息失败就关闭进程句柄,退出程序
if(dwRdAddr>0x140000)
{
cout<<"读取信息失败!"<<endl;
CloseHandle(hPro);
return 0;
}
//赋值 dwRdAddr 为注册码开始的位置
dwRdAddr-=6;
//输出注册码开始的内存地址的十六进制值
cout<<"RegCode Address: 0x"<<hex<<dwRdAddr<<endl;
//把注册码读取到UsrKey
ReadProcessMemory(hPro,(LPVOID)dwRdAddr,UsrKey,28,NULL);
TerminateProcess(hPro,0);
CloseHandle(hPro);
//格式化十六进制值为ASCII格式注册码
sprintf(st,"%s",UsrKey);
//输出注册信息
cout<<endl<<"RegUser: "<<userName<<endl;
cout<<"RegCode: "<<st<<endl;
//暂停
system("pause >nul");
return 0;
}
--------------------------------------------------------------------------------
【一点随想】
1、很多东西完全搞懂,完全弄明白固然很好,但是很多事情我们是没有时间去弄明白,搞清楚的。就像我们的文字是汉字,
汉字是谁的发明不可考了;就像我们整天用电脑,我们未必需要具体知道CPU的细节,主板的每个元件。时光匆匆,有些东
西好用、会用就行。
2、虽然解决问题的方法有高低之分,但是能实质性分析并解决问题也不错。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年09月23日
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课