|
本帖最后由 镜中神无 于 2017-3-24 20:54 编辑
QQ豪迪群发这玩意确实是被玩烂了,我汗……
听说每月教程前3有大大的奖励,我这个菜鸡也就厚着脸皮来凑个热闹。
我个人的思路是:
1.找到全局变量
2.写个DLL,导入进去,在该全局变量上写下内存写入断点
3.中断的时候就修改全局变量的值
4.HOOK CreateFileA,解决掉自校验
(这样搞能不能发我也不知道,我用的是QQ国际版,无法测试)
按传统套路来说是手动去自校验,逆向。但我是懒人,听说懒是聪明的表现,所以能懒我就尽量懒。其实也可以直接dll劫持,这样就不用考虑去自校验了,但是一个一个添加导出函数原型好累的说。
本人学艺不精,标准菜鸡一只,如有错误,还望指正,本人不胜感激。
豪迪软件官网:8222.com
下载地址:http://115.28.32.153/d/QQSend1.zip
解压,基本套路就不详细讲了。
直接OD载入,搜索UNICODE字符串引用,找到“已注册”字样,进入,发现如下代码。
005549B8 |. 803D DC405900>cmp byte ptr [5940DC], 0 ; 验证BYTE PTR[5940DC]的值是否为0
005549BF |. 74 10 je short 005549D1 ; 为0则JE跳,未注册
005549C1 |. BA 8C4A5500 mov edx, 00554A8C ; 已注册版本
005549C6 |. 8B83 FC020000 mov eax, dword ptr [ebx+2FC]
005549CC |. E8 BF82FAFF call 004FCC90
005549D1 |> A1 D0405900 mov eax, dword ptr [5940D0]
我们得到了全局变量的地址,5940DC(当然你也可以写个特征码搜索,再来个DLL劫持,直接通杀各版本豪迪)
个人去自校验的思路是,备份一份未修改的程序,HOOK CreateFileA,如果程序想要打开自身数据进行校验,我就修改参数,让它打开未修改的程序。
注意请把未修改的qqqf.exe改名为qqqf.exe.bak,放于同一目录下,否则代码无法正常工作!
请在XP及以上系统运行,否则代码无法正常工作!
下面贴上完整代码(Delphi)
实际用内存断点的时候需要考虑跨断点长度,此处为1字节长度,故无需考虑断点长度,跨分页等问题,实际使用的时候需要注意。
(想想自己能记得清的算法已经不多了,链表就是其中的一个,老师教的东西都还回去了,唉……)[Delphi] 纯文本查看 复制代码 library Patch;
uses
Windows,
SysUtils,
Classes;
type
EXCEPTION_POINTERS = record
ExceptionRecord: ^_EXCEPTION_RECORD;
ContextRecord: ^_CONTEXT;
end;
PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
PLink = ^Link; //线程单向链表结构,触发单步异常需要使用
Link = record
dwThreadId: Cardinal; //线程ID
bStates: Boolean; //True需要写入全局变量,False不需要
pNext: PLink;
end;
const
pVar: Pointer = Pointer($5940DC); //全局变量地址
EXCEPTION_CONTINUE_EXECUTION = -1;
EXCEPTION_CONTINUE_SEARCH = 0;
var
bCode: array[0..4] of Byte;
pApiFunc: Pointer;
iBegin: Cardinal; //内存分页开始地址
iEnd: Cardinal; //内存分页结束地址
pHead: PLink = nil; //链表头部
iProtect: Cardinal;
bTrue: Boolean = True;
{$R *.res}
{$J-}
procedure GetJmpCode(pCode, pJmp: Cardinal; var bMachine: array of Byte); //计算jmp xxxxxxxx机器码,第一个参数是源地址,第二个是目标地址,第三个是储存机器码的数组变量
var
iRVA: Cardinal;
begin
iRVA := pJmp - pCode - 5;
bMachine[0] := $E9;
CopyMemory(@bMachine[1], @iRVA, 4);
end;
function MyCreateFileA(szFileName: PAnsiChar; dwDesiredAccess: Cardinal; dwShareMode: Cardinal; lpSecurityAttributes: PSECURITY_DESCRIPTOR; dwCreationDisposition: Cardinal; dwFlagsAndAttributes: Cardinal; hTemplateFile: Cardinal): Cardinal; stdcall
var
sFile: string;
wsFile: PWideChar;
begin
//这里不考虑还原API头部5字节,直接调用W版本的API,XP及以上是A版转为W版,XP以下是W版转A版
//故本代码无法运行在XP以下
//而且本代码使用的VEH也是XP才支持的
SetLength(sFile, 260);
GetModuleFileName(0, PAnsiChar(sFile), 260);
sFile := StrPas(PAnsiChar(sFile));
if UpperCase(szFileName) = UpperCase(sFile) then
begin
sFile := ExtractFilePath(StrPas(szFileName));
sFile := sFile + 'qqqf.exe.bak';
GetMem(wsFile, (Length(sFile) + 1) * 2);
StringToWideChar(sFile, wsFile, Length(sFile) + 1);
Result := CreateFileW(wsFile, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
FreeMem(wsFile);
end
else
begin
GetMem(wsFile, (Length(szFileName) + 1) * 2);
StringToWideChar(StrPas(szFileName), wsFile, Length(szFileName) + 1);
Result := CreateFileW(wsFile, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
FreeMem(wsFile);
end;
end;
function VectoredHandler(ExceptionInfo: PEXCEPTION_POINTERS): Integer; stdcall
var
pTmpLink: PLink;
pJLink: PLink;
begin
case ExceptionInfo.ExceptionRecord.ExceptionCode of
EXCEPTION_ACCESS_VIOLATION: //越权访问异常
begin
if ExceptionInfo.ExceptionRecord.ExceptionInformation[0] = 1 then //写操作
begin
if (ExceptionInfo.ExceptionRecord.ExceptionInformation[1] >= iBegin) and (ExceptionInfo.ExceptionRecord.ExceptionInformation[1] <= iEnd) then
begin
if ExceptionInfo.ExceptionRecord.ExceptionInformation[1] = Cardinal(pVar) then
begin
if pHead = nil then //如果链表头部为空指针
begin
New(pHead);
pHead.dwThreadId := GetCurrentThreadId();
pHead.bStates := True;
pHead.pNext := nil;
end
else
begin
New(pTmpLink);
pJLink := pHead;
while pJLink.pNext <> nil do //添加到链表末尾
begin
pJLink := pJLink.pNext;
end;
pJLink.pNext := pTmpLink;
pTmpLink.bStates := True;
pTmpLink.pNext := nil;
end;
end
else
begin
if pHead = nil then //如果链表头部为空指针
begin
New(pHead);
pHead.dwThreadId := GetCurrentThreadId();
pHead.bStates := False;
pHead.pNext := nil;
end
else
begin
New(pTmpLink);
pJLink := pHead;
while pJLink.pNext <> nil do //添加到链表末尾
begin
pJLink := pJLink.pNext;
end;
pJLink.pNext := pTmpLink;
pTmpLink.bStates := False;
pTmpLink.pNext := nil;
end;
end;
VirtualProtect(Pointer(iBegin), iEnd - iBegin + 1, 4, iProtect);
ExceptionInfo.ContextRecord.EFlags := ExceptionInfo.ContextRecord.EFlags or $100; //设置线程TF位
Result := EXCEPTION_CONTINUE_EXECUTION; //处理异常
end
else
Result := EXCEPTION_CONTINUE_SEARCH;
end
else
Result := EXCEPTION_CONTINUE_SEARCH;
end;
EXCEPTION_SINGLE_STEP:
begin
if pHead = nil then
Result := EXCEPTION_CONTINUE_SEARCH
else
begin
if pHead.pNext = nil then
begin
if pHead.dwThreadId = GetCurrentThreadId() then
begin
if pHead.bStates then
begin
CopyMemory(pVar, @bTrue, 1);
end;
VirtualProtect(pVar, 1, PAGE_READONLY, iProtect);
Dispose(pHead);
pHead := nil;
Result := EXCEPTION_CONTINUE_EXECUTION;
end
else
Result := EXCEPTION_CONTINUE_SEARCH;
end
else
begin
pTmpLink := pHead;
pJLink := pHead;
while pTmpLink <> nil do
begin
if pTmpLink.dwThreadId = GetCurrentThreadId() then
begin
pJLink.pNext := pTmpLink.pNext;
if pTmpLink.bStates then
begin
CopyMemory(pVar, @bTrue, 1);
end;
VirtualProtect(pVar, 1, PAGE_READONLY, iProtect);
Dispose(pTmpLink);
Result := EXCEPTION_CONTINUE_EXECUTION;
Exit;
end;
pJLink := pTmpLink;
pTmpLink := pTmpLink.pNext;
end;
end;
end;
end;
else
Result := EXCEPTION_CONTINUE_SEARCH; //不处理异常
end;
end;
procedure Main();
type
TAddVectoredExceptionHandler = procedure (First: Cardinal; pFunc: Pointer); stdcall;
var
hModule: Cardinal;
iProtect: Cardinal;
pFunc: TAddVectoredExceptionHandler;
stInfo: SYSTEM_INFO;
begin
hModule := GetModuleHandle('kernel32.dll');
if hModule = 0 then
hModule := LoadLibrary('kernel32.dll');
pApiFunc := GetProcAddress(hModule, 'CreateFileA');
pFunc := GetProcAddress(hModule, 'AddVectoredExceptionHandler');
pFunc(1, @VectoredHandler);
VirtualProtect(pApiFunc, 5, PAGE_EXECUTE_READWRITE, iProtect);
GetJmpCode(Cardinal(pApiFunc), Cardinal(@MyCreateFileA), bCode); //计算JMP机器码
CopyMemory(pApiFunc, @bCode, 5); //写入API头部,开始HOOK
GetSystemInfo(stInfo);
iBegin := (Cardinal(pVar) div stInfo.dwPageSize) * stInfo.dwPageSize;
iEnd := (Cardinal(pVar) div stInfo.dwPageSize + 1) * stInfo.dwPageSize;
VirtualProtect(pVar, 1, PAGE_READONLY, iProtect); //修改全局变量内存属性为只读
end;
exports
main;
begin
Main(); //安装APIHOOK,以及设置内存断点
end.
编译以后,把编译出来的Patch.dll放到群发器目录下,打开Lord_PE。
PE编辑器——目录——输入表后面的第一个按钮。
选中一项,右键——Add Import
点击确定,然后一路保存回去,打开就会发现有惊喜。
虽然弹出了网络验证失败的框框,但是我们还是注册成功了。
因为所有写入这个全局变量的代码都被我们用内存断点拦截下来了。
源码下载:
Patch QQSend1.rar
(46.91 KB, 下载次数: 65)
|
评分
-
参与人数 15 | 威望 +1 |
HB +37 |
THX +8 |
收起
理由
|
猫妖的故事
| |
|
+ 1 |
|
lies
| |
|
+ 1 |
|
消逝的过去
| |
+ 2 |
|
|
禽大师
| |
+ 1 |
|
|
sjtkxy
| |
+ 1 |
+ 1 |
|
bing_mao
| |
+ 1 |
|
|
zxjzzh
| |
|
+ 1 |
[吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守! |
一路走来不容易
| |
|
+ 1 |
|
叶落花开
| |
+ 2 |
|
|
hnymsh
| |
+ 2 |
|
|
丄床
| |
+ 2 |
+ 1 |
[快捷评语] - 2017,让我们17学破解! |
小莫同学
| |
+ 1 |
|
[快捷评语] - 吃水不忘打井人,给个评分懂感恩! |
小小橙
| |
+ 1 |
|
[快捷评语] - 分享精神,是最值得尊敬的! |
81NewArk
| |
+ 4 |
+ 1 |
[快捷评语] - 吃水不忘打井人,给个评分懂感恩! |
Shark恒
| + 1 |
+ 20 |
+ 1 |
[快捷评语] - 吃水不忘打井人,给个评分懂感恩! |
查看全部评分
|