废话不多说直接开干.众所周知现在那些"见不得人的产品"都是层层防护用来对抗游戏公司和同行!
其中不乏很多产品都是带着驱动上线的,但玩具是玩具产品就要有个产品的样子.
首先稳定性和兼容性一定要达标.下面我分享的这些技术方案是从运行了几年的成熟产品当中提取出来的并非凭空臆想请放心.
一个真正"见不得人"的产品其中包括几项必做 :
我们今天分享的主要内容就是无内存.
真正的无内存 = 看不到地址 + 即使有地址访问时崩溃
检验无内存是否合格的标准很简单,使用PCHunter看内存属性以及是否能拷贝出来.如果看不到并且直接输入地址也拷贝不到,编写驱动也无法访问就OK了
当初我的方案也是在搜索引擎输入了 “驱动隐藏内存” 找到了一篇文章对我的启发很大.最终经过几天的修改测试才得以落地!
理论知识下面这个链接说的很明白了我就不废话了:
https://www.cnblogs.com/onetrainee/p/11750274.html
但是他的这个方案有几个问题 :
另外我的代码基础是建立在Blackbone上面升级的.(github搜索Blackbone)
它是一个成熟的驱动程序,包括ring3通信.重点看 src/BlackBoneDrv/
BlackBoneTest 写了很多demo 简单看看就能学会如何加载并通信!
上图粉色框里面的3块内存是游戏的.很多人一看就知道是什么游戏了
下面蓝色框里面的2块内存是我们的.进程内仅当前内存块中可读写
下面开始阅读驱动代码 :
OK了。同学们快去调通源代码吧.
至于驱动怎么签名别来问我,但是我可以告诉你也就是几百块钱的事。一条烟钱吧
另外WIN10平台需要过PG,否则半小时蓝屏.
动态过pg推荐去看看(github.com/9176324/Shark)
不想编译的同学们可以直接点击右面的 releases 下载一个exe和Shark.sys
双击的时候自动加载Shark.sys帮你过PG,当然这个Shark.sys也需要找人去签名.
/
*
*
*
隐藏内存
*
IOCTL_BLACKBONE_HIDE_VAD 只能隐藏 Image
*
/
/
*
*
*
隐藏内存
*
IOCTL_BLACKBONE_HIDE_VAD 只能隐藏 Image
*
/
/
/
/
<summary>
/
/
/
hide memory ex
/
/
/
<
/
summary>
typedef struct _HIDE_MEMORYEX
{
ULONGLONG beginAddress;
ULONGLONG endinAddress;
ULONG pid;
/
/
Target process
ID
} HIDE_MEMORYEX,
*
PHIDE_MEMORYEX;
/
/
/
<summary>
/
/
/
hide memory ex
/
/
/
<
/
summary>
typedef struct _HIDE_MEMORYEX
{
ULONGLONG beginAddress;
ULONGLONG endinAddress;
ULONG pid;
/
/
Target process
ID
} HIDE_MEMORYEX,
*
PHIDE_MEMORYEX;
case IOCTL_BLACKBONE_HIDE_MEMORYEX:
{
if
(inputBufferLength >
=
sizeof(HIDE_MEMORYEX) && ioBuffer)
{
Irp
-
>IoStatus.Status
=
BBHideMemoryEx((PHIDE_MEMORYEX)ioBuffer);
}
else
{
Irp
-
>IoStatus.Status
=
STATUS_INFO_LENGTH_MISMATCH;
}
}
break
;
case IOCTL_BLACKBONE_HIDE_MEMORYEX:
{
if
(inputBufferLength >
=
sizeof(HIDE_MEMORYEX) && ioBuffer)
{
Irp
-
>IoStatus.Status
=
BBHideMemoryEx((PHIDE_MEMORYEX)ioBuffer);
}
else
{
Irp
-
>IoStatus.Status
=
STATUS_INFO_LENGTH_MISMATCH;
}
}
break
;
/
/
/
<summary>
/
/
/
Hide Memory containing target address
/
/
/
<
/
summary>
/
/
/
<param name
=
"pData"
>Address info<
/
param>
/
/
/
<returns>Status code<
/
returns>
NTSTATUS BBHideMemoryEx(IN PHIDE_MEMORYEX pData);
/
/
/
<summary>
/
/
/
Hide Memory containing target address
/
/
/
<
/
summary>
/
/
/
<param name
=
"pData"
>Address info<
/
param>
/
/
/
<returns>Status code<
/
returns>
NTSTATUS BBHideMemoryEx(IN PHIDE_MEMORYEX pData);
NTSTATUS BBHideMemoryEx(IN PHIDE_MEMORYEX pData)
{
NTSTATUS status
=
STATUS_SUCCESS;
PEPROCESS pProcess
=
NULL;
NTSTATUS status1
=
STATUS_SUCCESS;
NTSTATUS status2
=
STATUS_SUCCESS;
status
=
PsLookupProcessByProcessId((HANDLE)pData
-
>pid, &pProcess);
if
(NT_SUCCESS(status))
{
/
/
检查是不是已经保存了PID, pid在游戏的父进程当中保存过来
/
/
下面这个BBIsMemoryProcess,是我项目当中的检查函数.大家无需关心.因为我不想驱动谁给它一个指令都能工作
if
(BBIsMemoryProcess(pData
-
>pid))
{
PMMVAD_SHORT pVadShort1
=
NULL;
PMMVAD_SHORT pVadShort2
=
NULL;
status1
=
BBFindVAD(pProcess, pData
-
>beginAddress, &pVadShort1);
status2
=
BBFindVAD(pProcess, pData
-
>endinAddress, &pVadShort2);
if
(NT_SUCCESS(status1) && NT_SUCCESS(status2))
{
if
(BBHideMemoryProcess(pData
-
>pid, pVadShort1, pVadShort1
-
>StartingVpn))
{
/
/
隐藏内存
pVadShort1
-
>StartingVpn
=
pVadShort2
-
>EndingVpn;
}
else
{
status
=
STATUS_INVALID_PARAMETER;
}
}
else
{
status
=
STATUS_INVALID_PARAMETER;
}
}
}
else
{
DPRINT(
"BlackBone: %s: PsLookupProcessByProcessId failed with status 0x%X\n"
, __FUNCTION__, status);
}
if
(pProcess) {
ObDereferenceObject(pProcess);
}
return
status;
}
NTSTATUS BBHideMemoryEx(IN PHIDE_MEMORYEX pData)
{
NTSTATUS status
=
STATUS_SUCCESS;
PEPROCESS pProcess
=
NULL;
NTSTATUS status1
=
STATUS_SUCCESS;
NTSTATUS status2
=
STATUS_SUCCESS;
status
=
PsLookupProcessByProcessId((HANDLE)pData
-
>pid, &pProcess);
if
(NT_SUCCESS(status))
{
/
/
检查是不是已经保存了PID, pid在游戏的父进程当中保存过来
/
/
下面这个BBIsMemoryProcess,是我项目当中的检查函数.大家无需关心.因为我不想驱动谁给它一个指令都能工作
if
(BBIsMemoryProcess(pData
-
>pid))
{
PMMVAD_SHORT pVadShort1
=
NULL;
PMMVAD_SHORT pVadShort2
=
NULL;
status1
=
BBFindVAD(pProcess, pData
-
>beginAddress, &pVadShort1);
status2
=
BBFindVAD(pProcess, pData
-
>endinAddress, &pVadShort2);
if
(NT_SUCCESS(status1) && NT_SUCCESS(status2))
{
if
(BBHideMemoryProcess(pData
-
>pid, pVadShort1, pVadShort1
-
>StartingVpn))
{
/
/
隐藏内存
pVadShort1
-
>StartingVpn
=
pVadShort2
-
>EndingVpn;
}
else
{
status
=
STATUS_INVALID_PARAMETER;
}
}
else
{
status
=
STATUS_INVALID_PARAMETER;
}
}
}
else
{
DPRINT(
"BlackBone: %s: PsLookupProcessByProcessId failed with status 0x%X\n"
, __FUNCTION__, status);
}
if
(pProcess) {
ObDereferenceObject(pProcess);
}
return
status;
}
/
/
/
<summary>
/
/
/
Save Hide Memory Process
id
/
/
/
<
/
summary>
/
/
/
<param name
=
"pid"
>pid<
/
param>
/
/
/
<returns>Status code<
/
returns>
BOOLEAN BBHideMemoryProcess(IN size_t PID, IN VOID
*
pVadShort, IN size_t StartingVpn)
{
/
/
KdPrint((
"Hide Memory Process : %d\n"
, PID));
/
/
确认是否已经保存过
for
(
int
i
=
0
; i < CLIENT_NUMBER; i
+
+
)
{
ClientProcess
*
client
=
&clientList[i];
if
(client
-
>pid
=
=
PID)
{
for
(
int
j
=
0
; j < HIDE_MEMORY; j
+
+
)
{
ClientMemory
*
memory
=
&client
-
>hideList[j];
if
(memory
-
>pVadShort !
=
NULL && memory
-
>startingVpn !
=
0
)
{
if
(memory
-
>pVadShort
=
=
pVadShort && memory
-
>startingVpn
=
=
StartingVpn)
return
TRUE;
}
}
for
(
int
j
=
0
; j < HIDE_MEMORY; j
+
+
)
{
ClientMemory
*
memory
=
&client
-
>hideList[j];
if
(memory
-
>pVadShort
=
=
NULL && memory
-
>startingVpn
=
=
0
)
{
memory
-
>pVadShort
=
pVadShort;
memory
-
>startingVpn
=
StartingVpn;
return
TRUE;
}
}
return
FALSE;
}
}
return
FALSE;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!