
.子程序 隐藏进程, 逻辑型, 公开
.参数 pid, 整数型, 可空, 空为隐藏本进程,可输入其它进程PID
.局部变量 eprocess, 长整数型
.局部变量 hand, 整数型
.局部变量 temp, 字节集
.局部变量 fw_, 长整数型
.局部变量 bw_, 长整数型
.局部变量 fw, 字节集
.局部变量 bw, 字节集
.如果 (是否为空 (pid))
hand = OpenProcess (2075311, 0, GetCurrentProcessId ())
eprocess = 取进程EProcess (GetCurrentProcessId ())
CloseHandle (hand)
.否则
eprocess = 取进程EProcess (pid)
.如果结束
.如果真 (eprocess = 0)
返回 (假)
.如果真结束
temp = 读物理内存 (eprocess + 136, 4)
.如果真 (temp = )
返回 (假)
.如果真结束
fw_ = 取字节集数据 (temp, #长整数型, )
fw = temp
temp = 读物理内存 (eprocess + 140, 4)
.如果真 (temp = )
返回 (假)
.如果真结束
bw_ = 取字节集数据 (temp, #长整数型, )
bw = temp
.如果真 (写物理内存 (fw_ + 4, bw) = -1)
返回 (假)
.如果真结束
.如果真 (写物理内存 (bw_, fw) = -1)
返回 (假)
.如果真结束
返回 (真)
//读物理内存
.版本 2
.子程序 读物理内存, 字节集
.参数 地址, 长整数型
.参数 长度, 整数型, , <=4096
.局部变量 MEMORY_CHUNKS, 字节集
.局部变量 ret, 字节集
.局部变量 retlen, 整数型
ret = 取空白字节集 (长度)
MEMORY_CHUNKS = 取字节集左边 (到字节集 (地址), 4) + 到字节集 (取指针_字节集 (ret, ret, 0)) + 到字节集 (长度)
NtSystemDebugControl (#SysDbgReadVirtualMemory, MEMORY_CHUNKS, 12, 0, 0, retlen) ' 12为MEMORY_CHUNKS的长度
.如果真 (retlen ≤ 0)
ret =
.如果真结束
返回 (ret)
//写物理内存
.版本 2
.子程序 写物理内存, 整数型
.参数 地址, 长整数型
.参数 数据, 字节集, , <=4096
.局部变量 MEMORY_CHUNKS, 字节集
.局部变量 ret, 整数型
.局部变量 retlen, 整数型
.局部变量 len, 整数型
len = 取字节集长度 (数据)
MEMORY_CHUNKS = 取字节集左边 (到字节集 (地址), 4) + 到字节集 (取指针_字节集 (数据, 数据, 0)) + 到字节集 (len)
NtSystemDebugControl (#SysDbgWriteVirtualMemory, MEMORY_CHUNKS, 12, 0, 0, retlen) ' 12为MEMORY_CHUNKS的长度
.如果真 (retlen ≤ 0)
ret = -1
.如果真结束
返回 (ret)
//取进程EProcess
.版本 2
.子程序 取进程EProcess, 长整数型
.参数 pid, 整数型
.局部变量 ret
.局部变量 信息块, 字节集
.局部变量 retlen
.局部变量 temp, SYSTEM_HANDLE_INFORMATION
.局部变量 信息块指针偏移
.局部变量 number
.局部变量 结果, 长整数型
retlen = 1
.循环判断首 ()
信息块 = 取空白字节集 (retlen)
ret = ZwQuerySystemInformation (#system_handle_infomation, 信息块, retlen, 0)
.如果 (ret = #STATUS_INFO_LENGTH_MISMATCH)
retlen = retlen × 2
信息块 = 取空白字节集 (retlen)
.否则
跳出循环 ()
.如果结束
.循环判断尾 (ret = #STATUS_INFO_LENGTH_MISMATCH)
信息块指针偏移 = 取指针_字节集 (信息块, 信息块, 0)
RtlMoveMemory3 (number, 信息块指针偏移, 4)
信息块指针偏移 = 信息块指针偏移 + 4
.计次循环首 (number, )
RtlMoveMemory2 (temp, 信息块指针偏移, 16)
.如果真 (pid = temp.ProcessId 且 temp.ObjectTypeNumber = 5)
返回 (十六文本至长整数 (取十六进制文本 (temp.Object)))
.如果真结束
信息块指针偏移 = 信息块指针偏移 + 16
.计次循环尾 ()
返回 (0)
以上是隐藏进程的源码
_启动窗口.可视 = 假
这个是隐藏 当前窗口 的代码
以上代码可能挺乱的,好好看看吧!
希望对你有帮助!
只让同时开一个?比如飞信是吗?那种的不行,就可以一个,我也不知道C#如何实现
QQ那类就可以多开
如果你说的是你自己的程序应该就可以多开
windows系统下,程序防止多开的几种常见方法:
1)使用FindWindow API函数。
通过查找窗口标题(或/和类名)来判断程序是否正在运行。如果找到了,表明程序正在运行,这时可退出程序,达到不重复运行的效果;反之表明程序是第一次运行。
这种方法不适用于以下情况,程序的标题是动态变化的、系统中运行了相同标题(或/和类名)的程序
2)Mutex/Event/Semaphore
通过互斥对象/信号量/事件等线程同步对象来确定程序是否已经运行。最常用的函数如:CreateMutexA(注意:QQ堂、QQ游戏大厅就是采用这样方法来限制程序多开的)
3)内存映射文件(File Mapping)
通过把程序实例信息放到跨进程的内存映射文件中,也可以控制程序多开。
4)DLL全局共享区
DLL全局共享区在映射到各个进程的地址空间时仅被初始化一次,且是在第一次被windows加载时,所以利用该区数据就能对程序进行多开限制。
5)全局Atom
将某个特定字符串通过GlobalAddAtom加入全局原子表(Global Atom Table),程序运行时检查该串是否存在来限制程序多开。(该Atom不会自动释放,程序退出前必须调用GlobalDeleteAtom来释放Atom)
6)检查窗口属性
将某些数据通过SetProp加入到指定窗口的property list,程序运行时枚举窗口并检查这些数据是否存在来限制多开。
以上只列举了最常见的几种方法,具体应用中可以有n种选择,或综合运用多种方法来限制。
上面说过,QQT采用CreateMutex函数来限制多开,那么我怎么知道是使用这个函数来限制的呢?
答案就是跟踪程序,查找程序是使用哪种方法来限制的。比如先看看是否使用CreateMutex来限制,如果不是,再看看是不是使用FindWindow,以此类推,直到找到方法为止。当然,有些程序也会综合使用多种方法来限制多开,方法也是一样的,只是麻烦点而已。
下面讲一讲使用CreateMutex函数来限制多开的方法:
CreateMutex函数声明如下(具体请查阅相关资料,如MSDN)
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,// pointer to security attributes
BOOL bInitialOwner, // flag for initial ownership
LPCTSTR lpName// pointer to mutex-object name
)
以下是使用CreateMutex函数来限制多开的典型delphi代码
hMutex:=CreateMutex(nil,TRUE,'qqtang')//建立互斥量
// 调用失败? 已经存在?
if(hMutex=0) or (GetLastError=ERROR_ALREADY_EXISTS)then
begin
//程序第二(或以上)次运行时,GetLastError会返回ERROR_ALREADY_EXISTS,表明互斥量已存在
//可以在这里编写退出代码
end
该段代码首先调用CreateMutex函数创建一名为 qqtang 的互斥对象,如果调用CreateMutex函数失败(hMutex=nil)或互斥对象早已存在(GetLastError=ERROR_ALREADY_EXISTS),则退出程序。
好了,明白上面的内容后,我们进入修改实战:
下载OllyDbg V1.1,解压到任何目录即可使用。
启动OllyDbg,打开QQT目录下的Core.dll文件,按[是]载入DLL文件。
按Ctrl+N打开API调用列表,找到CreateMutexA后按回车,在d出的窗口里双击第一行来到CPU窗口,反汇编代码如下:
10002FB9 . 51 push ecx /MutexName = "qqtang"
10002FBA . 6A 01 push 1 |InitialOwner = TRUE
10002FBC . 6A 00 push 0 |pSecurity = NULL
10002FBE . FF15 60E40010 call dword ptr [<&KERNEL32.CreateMutexA>] \CreateMutexA 建立互斥量
10002FC4 . 8B95 D4FEFFFF mov edx,dword ptr [ebp-12C]
10002FCA . 8902 mov dword ptr [edx],eax
10002FCC . 8B85 D4FEFFFF mov eax,dword ptr [ebp-12C]
10002FD2 . 8338 00 cmp dword ptr [eax],0 检查CreateMutexA函数是否调用失败
10002FD5 . 0F84 CD000000 je Core.100030A8 把je改为jmp即可
10002FDB . FF15 5CE40010 call dword ptr [<&KERNEL32.GetLastError>] [GetLastError
10002FE1 . 3D B7000000 cmp eax,0B7 检查对象是否已存在
10002FE6 . 0F85 BC000000 jnz Core.100030A8 (也可以在这里把jnz改为jmp)
10002FEC . 8B8D D4FEFFFF mov ecx,dword ptr [ebp-12C]
10002FF2 . C701 00000000 mov dword ptr [ecx],0
10002FF8 . 6A 00 push 0 /Title = NULL
10002FFA . 68 5CC60010 push Core.1000C65C |Class = "QQTangWinClass"
10002FFF . 6A 00 push 0 |hAfterWnd = NULL
10003001 . 6A 00 push 0 |hParent = NULL
10003003 . FF15 40E70010 call dword ptr [<&USER32.FindWindowExA>] \FindWindowExA 查找QQT窗口
选中这行:
10002FD5 . 0F84 CD000000 je Core.100030A8
然后按空格,在d出的窗口中把“je 100030A8”修改为“jmp 100030A8”,按[汇编]。
右键单击CPU窗口,在d出菜单中选“复制到可执行文件”-》“所有改动”,选[全部复制]。右键单击d出的窗口,选“保存文件”保存即可。
是否觉得上面的修改比较麻烦呢?呵呵,授人于鱼不如授人于渔,上面是告诉你为什么要这样修改,修改的原理是什么,你明白修改原理后,有新版本时你就可以自己修改了。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)