因为一直没有钻研,所以很久没有写这种技术性的文章了。这两天颇有收获,如果不记录下来恐怕日后遗忘。按理说应该写到我的CSDN博客上,但是那里已经荒废很久了,而空间又很久没有更新了,所以还是两边都发布一下吧
首先声明,虽然很有成就感,但是没有什么技术含量,想学技术的同学请直接关闭网页绕行。
几次破解都成功了,都是机缘巧合,不知道是我运气好还是我确实有这个能力,反正自我满足了一把,呵呵
第一次是去年,一个朋友弄了个软件,想大批量使用,但是只有几个注册码,于是我去想办法。据我微薄的经验,注册码一般无非就是几个地方,硬件ID(主板啦,硬盘啦,网卡的mac地址啦),于是几个都试了一下,都不是,很是郁闷,后来有一台已经注册好的机器重装,注册码没变,结果软件不能用了,很奇怪,难道不是绑定的硬件,竟然是windows系统信息不成?
又尝试恢复几个地方到重装前的环境,终于在把机器名改回原来之后,软件可以运行了。nnd,这货竟然绑定了机器名!
接下来的工作就简单了,呵呵,你懂的,当然不是把所有机器都改成一个名字,那在网络上早冲突了,所有的机器用的都是一个注册码,我要做的只是给这个程序加了一个壳,在运行之前把机器名改为注册码里的机器名,然后调用程序,调用起来之后再把机器名改回去。
就是这么简单。你看,我就说没有什么技术含量嘛。就像变魔术,揭穿了所有人都会说:“嗨,这么容易”。当然魔术的效果是不错的,那一段时间很是膨胀了一把。
简单附几行改机器名的代码,主要是针对注册表操作,而注册表里放机器名的地方也很多,要找到哪个是【我的电脑】-属性-计算机名里显示的那个,还真是费了一点工夫呢
前面略
……
Memo1.Lines.Clear;
len:=30;
getmem(lna,30);
getcomputername(lna,len);
Memo1.Lines.Add('getname1='+lna);//运行之前显示一下机器名
Myreg:=Tregistry.Create; //创建一个Tregistry实例
Myreg.RootKey:=HKEY_LOCAL_MACHINE; //设置根键
if Myreg.openkey('SYSTEM/CurrentControlSet/Control/ComputerName/ActiveComputerName',FALSE) then
begin
str[4]:=Myreg.readstring('ComputerName');
Memo1.Lines.Add('str4='+str[4]);
if str[4]='' then
begin
Button2.Enabled:=false;
Myreg.closekey;
exit;
end;
Myreg.WriteString('ComputerName','20081016-1927');//改名
Myreg.closekey;
end;
len:=30;
getmem(lna,30);
GetComputerName(lna,len);//取机器名,看是否修改
Memo1.Lines.Add('getname2='+lna);//显示一下修改后的机器名
调用起来程序后,再改回去
if Myreg.openkey('SYSTEM/CurrentControlSet/Control/ComputerName/ActiveComputerName',FALSE) then
begin
if str[4]<>'' then
Myreg.WriteString('ComputerName',str[4]);
Myreg.closekey;
end;
len:=30;
getmem(lna,30);
getcomputername(lna,len);
Memo1.Lines.Add('getname3='+lna);//再显示一下机器名
Close;
重点还是说说今天这次。这两天父母有事回家,我和媳妇宅在家里看孩子,闲着没事,网上的一个朋友,让我帮忙做一个调用外挂的程序,谈不上破解,只不过这个外挂程序弹出的确定窗口太多,想让我的程序调用后自动取消弹出窗口,隐藏那个外挂程序, 显示我的程序。有点意思,就答应了。
有点难度的是那个外挂程序加了防调用机制,直接运行可以,不能在程序里调用。
拿到那个外挂后,我先试了试双击运行,当然是没问题的。
然后建立一个快捷方式,双击快捷方式运行,也是可以的。
下一步,写一个批处理运行这个程序,防调用机制起作用了,没成功。
批处理运行快捷方式,也没成功。
写程序尝试了一下,winexec和shellexecute调用,意料之中的失败。
到这一步应该都明白了,这货肯定判断了父进程ID是不是explorer
我这个人最擅长的就是不按牌理出牌,按理说到了这一步,很多人想到应该就是注入explorer调用了,高手可能会修改PEB或者用BHO之类其他更高级的方式,但是我没有,而且我在那哥们给我程序之后不到20分钟就把能成功调用外挂的程序发给他了。
我是怎么做到的?嘿嘿,简单到没法再简单,我只不过是打开了外挂程序所在文件夹并且选中它,然后发送了一个回车而已。
那哥们兴奋的说:你真行,我看好你哦。
当然,后面还有很多工作要做,又要隐藏外挂窗口,又要自动点外挂弹出的确定,还有关闭我的程序之前先关闭外挂,弄的我今天忙活了一天现在才弄完,后面这些更没有技术含量了,全是体力劳动。
今天主要的工作还在于完善调用上,总不好每次点按钮的时候先打开一个文件夹窗口再关闭吧?其他方法呢,注入explorer太危险,很容易引起系统崩溃,我又试了试CreateProcess之类的调用,结果是一个样,绕了一圈还是回到起点来。
那就完善最初的方案吧,首先,把打开外挂文件夹并选中这步由显式打开变成隐式打开,这步很简单,只需要修改
WinExec的第二个参数由SW_NORMAL为SW_HIDE就OK。
接下来试了试SetForegroundWindow激活和发送按键,竟然一样可以用,这难道就是运气?或者说传说中的人品?
(因为之前测试的时候如果有相同的文件夹在打开,文件选中功能是不好使的,于是我在打开文件夹后又调用postmessage(h,wm_char,ord(s[i]),0);来选中文件,至于发送按键,用的更是最基本的keybd_event,这个东东可不管你要给谁发送,他是逮着谁是当前激活窗口就往谁那发,比如我在一个程序里写按钮按下两秒钟后通过keybd_event发送一个a,那么我按下按钮后立即打开一个文本,2秒钟后文本里就会出现一个a,所以说对一个看不到的窗体我发送回车竟然能成功,这不是上天助我是什么呢)
说一下这里面用到的几个技术点吧,为此我还查了我05年在CSDN写的博客,6年过去了一点进步都没有,狠狠的BS自己一下,都没有什么技术含量了,自己备忘一下
查找窗体句柄用
function GetWindow2(btitile:string):HWND;
var winhandle: Hwnd;
winprocess: Dword;
title:pchar;
WndClassName: array[0..254] of char;
begin
result:=0;
Getmem(title,255);
winhandle:=GetWindow(GetForeGroundWindow,GW_HWNDFIRST);
while winhandle <> 0 do
begin
if (IsWindowEnabled(winhandle) and IsWindow(winhandle)) then
begin
// GetWindowThreadProcessId(winhandle,@winprocess);
GetWindowText(winhandle,title,255);
if (pos(btitile,title)>0) then//这里判断的只有包含就列出,当然也可以根据情况改成=
begin
if not IsWindowVisible(winhandle) then//这里是看窗体是否可见 当然看不见的才是我想要的
begin
GetClassName(winhandle, @WndClassName, 254);//判断一下窗体的类
Form1.Memo1.Lines.Add(IntToStr(winhandle)+' '+ WndClassName+' '+title ) ;
// CabinetWClass;
result:=winhandle;
end;
end;
end;
winhandle:=GetWindow(winhandle,GW_HWNDNEXT);
end;
Freemem(title);
CloseHandle(winHandle);
end;
其中的btitile是你要查的窗体标题
找到句柄后要干什么不就随我了
ShowWindow(clhandle,SW_HIDE)是隐藏窗体
ShowWindow(clhandle,SW_SHOW)是显示窗体
procedure TForm1.Button3Click(Sender: TObject);
var
Process, ProcessId: Cardinal;
begin
clhandle:=0;
GetWindow1;//找外挂窗口句柄
if clhandle>0 then//如果找到则关闭
Begin
GetWindowThreadProcessId(clhandle, ProcessId);
Process := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId);
//CloseHandle(clhandle);
TerminateProcess(Process,0);//根据句柄强制结束进程
End;
close;
end;