flag:
1.
首先是解密文件名,然后打开文件,获取文件大小,申请同样大小的内存,然后将目标文件读到内存中。
2.
IDA动态追踪了一下,发现打开的标志是 OPEN_EXISTING,但是并没有提供 hack.dat 这个文件。
于是我创建了个hack.data 这个文件,内容随机写了一串字符串"1111111111111111111"。
3.
读取文件之后,发现调用了一个算法函数,然后计算了另一个函数的大小,然后将算法函数申请的内存的值,赋给ProcName,发现这个ProcName的大小正好是"ShooterClient.exe"的长度。
所以推测为:前面的一系列操作,目的是解密出游戏的进程名,加密字符串的目的是规避字符串检测。
然后,后面的进程快照的遍历,证实了这个推测。
4.
然后进程快照遍历,通过字符串对比,找到游戏进程的PID。
为了方便,直接通过x64dbg,在OpenProcess调用前,修改PID参数为游戏进程。
5.
然后是 GetProcAddress了五次,
获取了LdrLoadDLL (LoadLibrary),RtlInitAnsiString,RtlFreeUnicodeString,LdrGetProcedureAddress(GetProcAddress),NtAllocateVirtual,RtlAnsiStringtoUnicodeString。
先是猜测注入,然后发现是修复DLL的导入表。
5.
最后是,在游戏进程申请一块内存,然后写入ShellCode,首先写入了一个DLL,然后写入了一个函数(ShellCode),最后写入一个缓冲区。
最后是创建一个远程线程,执行函数。
6.
效果就是右键自瞄,但是没有判断障碍物。
7.
继续x64dbg追踪,先是从内存中dump下来要注入的dll文件。
8.
在游戏进程内追踪Shellcode。
发现先是调用NtVirtualAllocate 申请内存后,把注入的DLL贴过来。
然后是通过LdrLoadDLL和LdrGetProcudre 来修复DLL的导入表
user32.dll
9.最后是调用DllEntry。
10.分析DLL的功能实现
这里发现输出flag:开启自瞄成功
这里发现是三角函数自瞄。
11.
自己写自瞄。
1.首先写个注入
因为提示不用在意注入方式和读写方式,所以采用简单的远程线程注入,不使用外挂程序提供的内存注入。
用dump出来的dll测试注入,注入成功。
2.
写个外部自瞄的DLL,自瞄热键同样设置为鼠标右键。
(2).跑完了整个流程,然后对加密细节进行分析。
1.先回到我dump dll的地方。
发现在VirtualProtect前,调用了一次算法函数,注意这里传入的大小为64000(0xFA00),是我们dump出来的DLL的大小。
2.进入算法函数。
发现有两个分支,因为整个过程调用了两次算法函数,一次传入hack.dat的内容,一次传入一个dll。分别对应了这两个分支。
3.退出算法函数,往上追。
发现了一个坑,刚开始看到sleep(5000),我一直以为是延时注入,并没有想到这里是printf(),所以在这里栽了个坑。
因为这里printf了一个字符串,猜测前面有字符串比较或者解密,继续往上追。
4.往printf上追
发现了一个字符串的初始化和解密。在解密完这个字符串后,然后和hack.data的内容进行一个字节一个字节的对比,相同则输出flag。
5.现在整个解密流程已经明显了,先是读入hack.dat的内容,然后调用算法函数走第二个分支解密,然后初始化和解密一个字符串,如果hack.dat的解密内容和字符串一致,则输出flag。
6.还原hack.dat
7.细节说明:
buffer的内容是我直接从动态调试的IDA里拷贝出来的。
注意:还原的hack.dat的内容应该以0x2C结尾,(0x2C解密后就是0),不用0结尾,对比一直失败,算是一个小坑吧。
8.总结一下,逆向很吃经验,但是也不能完全依靠经验,上文中,笔者就是完全依靠经验,忽略了printf函数,栽了个大跟头。所以大家在逆向小程序的时候,最好是把所有分支走一遍。
注意:Eprocess
+
0x2d8
ImageFileName : [
15
] UChar
进程快照遍历的只是进程名的前
15
个字节。
注意:Eprocess
+
0x2d8
ImageFileName : [
15
] UChar
进程快照遍历的只是进程名的前
15
个字节。
int
main()
{
HANDLE a
=
CreateFileA(
"C:\\Users\\TalShang\\Desktop\\PC客户端题目\\复赛\\dump dll\\Project1\\Project1\\dump.dll"
,
FILE_ALL_ACCESS,TRUE,NULL, OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,
0
);
DWORD pid
=
0x4028
;
HANDLE handle
=
OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
/
*
DWORD b
=
GetLastError();
printf(
"Error:%x"
,b);
*
/
DWORD64 addr
=
0x000001B7F00C9080
;
char
*
mem
=
(char
*
)malloc(
0xFA00
);
SIZE_T readSize
=
0
;
ReadProcessMemory(handle,(LPVOID)addr,mem,
0xFA00
,&readSize);
WriteFile(a, mem,
0xFA00
,NULL,NULL);
system(
"pause"
);
CloseHandle(a);
CloseHandle(handle);
return
0
;
}
int
main()
{
HANDLE a
=
CreateFileA(
"C:\\Users\\TalShang\\Desktop\\PC客户端题目\\复赛\\dump dll\\Project1\\Project1\\dump.dll"
,
FILE_ALL_ACCESS,TRUE,NULL, OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,
0
);
DWORD pid
=
0x4028
;
HANDLE handle
=
OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
/
*
DWORD b
=
GetLastError();
printf(
"Error:%x"
,b);
*
/
DWORD64 addr
=
0x000001B7F00C9080
;
char
*
mem
=
(char
*
)malloc(
0xFA00
);
SIZE_T readSize
=
0
;
ReadProcessMemory(handle,(LPVOID)addr,mem,
0xFA00
,&readSize);
WriteFile(a, mem,
0xFA00
,NULL,NULL);
system(
"pause"
);
CloseHandle(a);
CloseHandle(handle);
return
0
;
}
int
main()
{
DWORD pid
=
21492
;
HANDLE handle
=
OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
if
(!handle)
return
0
;
PVOID mem
=
VirtualAllocEx(handle, NULL,
0x100
, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
char
*
Dllpath
=
(char
*
)
"C:\\Users\\TalShang\\Desktop\\PC客户端题目\\复赛\\dump dll\\Project1\\Project1\\dump.dll"
;
SIZE_T retSize
=
0
;
BOOLEAN isflag
=
WriteProcessMemory(handle, mem, Dllpath,strlen(Dllpath)
+
1
,&retSize);
if
(!isflag)
return
0
;
LPTHREAD_START_ROUTINE loadDll
=
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA(
"kernel32.dll"
),
"LoadLibraryA"
);
HANDLE thread
=
CreateRemoteThread(handle,NULL,NULL,loadDll,mem,NULL,NULL);
system(
"pause"
);
CloseHandle(thread);
CloseHandle(handle);
return
0
;
}
int
main()
{
DWORD pid
=
21492
;
HANDLE handle
=
OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
if
(!handle)
return
0
;
PVOID mem
=
VirtualAllocEx(handle, NULL,
0x100
, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
char
*
Dllpath
=
(char
*
)
"C:\\Users\\TalShang\\Desktop\\PC客户端题目\\复赛\\dump dll\\Project1\\Project1\\dump.dll"
;
SIZE_T retSize
=
0
;
BOOLEAN isflag
=
WriteProcessMemory(handle, mem, Dllpath,strlen(Dllpath)
+
1
,&retSize);
if
(!isflag)
return
0
;
LPTHREAD_START_ROUTINE loadDll
=
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA(
"kernel32.dll"
),
"LoadLibraryA"
);
HANDLE thread
=
CreateRemoteThread(handle,NULL,NULL,loadDll,mem,NULL,NULL);
system(
"pause"
);
CloseHandle(thread);
CloseHandle(handle);
return
0
;
}
/
/
此处我省略了部分内容,封装的读写没有贴出来。
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
typedef struct _MATRIX {
union {
struct {
float
_11, _12, _13, _14;
float
_21, _22, _23, _24;
float
_31, _32, _33, _34;
float
_41, _42, _43, _44;
};
float
m[
4
][
4
];
};
} Matrix;
typedef struct _VECTOR3 {
float
x;
float
y;
float
z;
} Vector3;
typedef struct _VECTOR2 {
float
x;
float
y;
} Vector2;
typedef struct TAimBot
{
bool
bLook;
ULONG64 dwObj;
ULONG64 dwObjMesh;
Vector3 Position;
FLOAT
Value1;
FLOAT
Value2;
}AimBot;
/
*
计算
2d
距离
*
/
float
Get2dDistance(
float
x1,
float
y1,
float
x2,
float
y2)
{
float
dDistance;
x1
=
x1
-
x2;
y1
=
y1
-
y2;
dDistance
=
sqrt(x1
*
x1
+
y1
*
y1);
return
dDistance;
}
/
*
计算
3d
距离
*
/
float
Get3dDistance(Vector3 MyPos, Vector3 TargerPos,
int
Divide)
{
float
fDistance;
Vector3 vec;
vec.x
=
TargerPos.x
-
MyPos.x;
vec.y
=
TargerPos.y
-
MyPos.y;
vec.z
=
TargerPos.z
-
MyPos.z;
fDistance
=
sqrt(
pow
(vec.x,
2
)
+
pow
(vec.y,
2
)
+
pow
(vec.z,
2
));
return
fDistance
/
Divide;
}
/
*
读坐标
*
/
Vector3 ReadVector3(ULONG64 addr, DWORD
Type
)
{
return
ReadMem<Vector3>(addr
+
Type
);
}
/
*
3d
-
>
2d
*
/
DWORD g_dwWidth,g_dwHeight;
bool
WorldToScreen_2D(Matrix viewWorld, Vector3 TargerPos, Vector2
*
result)
{
float
fViewW
=
viewWorld._14
*
TargerPos.x
+
viewWorld._24
*
TargerPos.y
+
viewWorld._34
*
TargerPos.z
+
viewWorld._44;
if
(fViewW <
0.01f
) {
return
false; }
fViewW
=
1
/
fViewW;
float
fBoxX
=
g_dwWidth
/
2
+
(viewWorld._11
*
TargerPos.x
+
viewWorld._21
*
TargerPos.y
+
viewWorld._31
*
TargerPos.z
+
viewWorld._41)
*
fViewW
*
g_dwWidth
/
2
;
float
fBoxY
=
g_dwHeight
/
2
-
(viewWorld._12
*
TargerPos.x
+
viewWorld._22
*
TargerPos.y
+
viewWorld._32
*
TargerPos.z
+
viewWorld._42)
*
fViewW
*
g_dwHeight
/
2
;
result
-
>x
=
fBoxX;
result
-
>y
=
fBoxY;
return
true;
}
/
*
读矩阵
*
/
void GetMatrix(ULONG64 Addr, Matrix
*
ViewWorld)
{
*
ViewWorld
=
ReadMem<Matrix>(ReadMem<ULONG64>(ReadMem<ULONG64>(Addr)
+
0x20
)
+
0x270
);
}
int
toMove(
int
a)
{
a
=
fabs(a);
if
(a >
200
)
return
50
;
else
if
(a >
100
)
return
25
;
else
if
(a >
80
)
return
25
;
else
if
(a >
60
)
return
20
;
else
if
(a >
45
)
return
15
;
else
if
(a >
20
)
return
5
;
else
if
(a >
9
)
return
3
;
else
if
(a >
3
)
return
1
;
return
0
;
}
void myMouseMove(
int
x,
int
y,
float
AimSpeed)
{
int
fTargetX
=
0
, fTargetY
=
0
;
fTargetX
=
x
-
g_dwWidth
/
2
;
fTargetY
=
y
-
g_dwHeight
/
2
;
if
(fTargetX >
0
)
fTargetX
=
toMove(fTargetX);
else
fTargetX
=
-
toMove(fTargetX);
if
(fTargetY >
0
)
fTargetY
=
toMove(fTargetY);
else
fTargetY
=
-
toMove(fTargetY);
mouse_event(
1
, fTargetX
/
AimSpeed, fTargetY
/
AimSpeed,
0
,
0
);
}
std::string GetObjectClassName(ULONG64 Gname, DWORD
ID
)
{
ULONG64 ulGname, ulTempAddr, ulTempAddr2;
DWORD Page, Order;
static char strObjectType[
64
]
=
{
"\0"
};
if
(
ID
>
0
&&
ID
<
2000000
)
{
ulGname
=
ReadMem<ULONG64>(Gname);
Page
=
ID
/
16384
;
Order
=
ID
%
16384
;
ulTempAddr
=
ReadMem<ULONG64>((ULONG64)(ulGname
+
Page
*
8
));
if
(ulTempAddr >
0
)
{
ulTempAddr2
=
ReadMem<ULONG64>(ulTempAddr
+
Order
*
8
);
if
(ulTempAddr2 >
0
)
{
ReadVirtual((LPVOID)(ulTempAddr2
+
12
), strObjectType,
64
*
sizeof(char));
}
}
}
return
strObjectType;
}
DWORD WINAPI start(DWORD Param)
{
/
/
AllocConsole();
/
/
SetConsoleCtrlHandler(NULL, true);
/
/
freopen(
"CONOUT$"
,
"w"
, stdout);
Matrix ViewWorld{};
AimBot aimBot;
Vector3 position;
Vector2 result{};
while
(true)
{
ULONG64 ulBase
=
(ULONG64)GetModuleHandle(NULL);
ULONG64 ulUworld
=
ReadMem<ULONG64>(ulBase
+
0x2F71060
);
ULONG64 ulGname
=
ulBase
+
0x2E6E0C0
;
ULONG64 ulMatrix
=
ulBase
+
0x2BF1100
;
ULONG64 ulUlevel
=
ReadMem<ULONG64>(ulUworld
+
0x30
);
ULONG64 ulActor
=
ReadMem<ULONG64>(ulUlevel
+
0x98
);
DWORD dwCount
=
ReadMem<DWORD>(ulUlevel
+
0xA0
);
GetMatrix(ulMatrix, &ViewWorld);
g_dwWidth
=
ReadMem<DWORD>(ulBase
+
0x2BF3240
);
g_dwHeight
=
ReadMem<DWORD>(ulBase
+
0x2BF3244
);
/
/
+
4
/
/
printf(
"%d %d %d %f\n"
, dwCount, g_dwWidth, g_dwHeight, ViewWorld._43);
for
(
int
i
=
0
; i < dwCount; i
+
+
)
{
ULONG64 ulObject
=
ReadMem<ULONG64>(ulActor
+
i
*
8
);
if
(ulObject <
0
)
continue
;
DWORD
id
=
ReadMem<DWORD>(ulObject
+
0x18
);
std::string strType
=
GetObjectClassName(ulGname,
id
);
if
(strType.find(
"BotPawn_C"
)
=
=
strType.npos)
continue
;
position
=
ReadVector3(ReadMem<ULONG64>(ulObject
+
0x158
),
0x1A0
);
if
(WorldToScreen_2D(ViewWorld, position, &result))
{
if
(!aimBot.bLook)
{
aimBot.Value1
=
Get2dDistance(g_dwWidth
/
2
, g_dwHeight
/
2
, result.x, result.y);
if
(aimBot.Value1 <
=
200.f
)
{
if
(aimBot.Value2
=
=
0
)
{
aimBot.Value2
=
aimBot.Value1;
aimBot.dwObj
=
ulObject;
}
else
if
(aimBot.Value1 < aimBot.Value2)
{
aimBot.Value2
=
aimBot.Value1;
aimBot.dwObj
=
ulObject;
}
}
}
}
}
if
(GetAsyncKeyState(
2
) !
=
0
)
{
aimBot.bLook
=
true;
position
=
ReadVector3(ReadMem<ULONG64>(aimBot.dwObj
+
0x158
),
0x1A0
);
if
(WorldToScreen_2D(ViewWorld, position, &result))
{
myMouseMove(result.x, result.y,
5
);
/
/
参数
3
是自瞄速度,如果自瞄乱晃就调高,这个是根据游戏灵敏度修正的,灵敏度高则需要调高。
}
}
else
{
aimBot.bLook
=
false;
aimBot.dwObj
=
0
;
aimBot.dwObjMesh
=
0
;
aimBot.Value1
=
0
;
aimBot.Value2
=
0
;
}
}
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE) start,NULL,NULL,NULL);
break
;
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
/
/
此处我省略了部分内容,封装的读写没有贴出来。
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
typedef struct _MATRIX {
union {
struct {
float
_11, _12, _13, _14;
float
_21, _22, _23, _24;
float
_31, _32, _33, _34;
float
_41, _42, _43, _44;
};
float
m[
4
][
4
];
};
} Matrix;
typedef struct _VECTOR3 {
float
x;
float
y;
float
z;
} Vector3;
typedef struct _VECTOR2 {
float
x;
float
y;
} Vector2;
typedef struct TAimBot
{
bool
bLook;
ULONG64 dwObj;
ULONG64 dwObjMesh;
Vector3 Position;
FLOAT
Value1;
FLOAT
Value2;
}AimBot;
/
*
计算
2d
距离
*
/
float
Get2dDistance(
float
x1,
float
y1,
float
x2,
float
y2)
{
float
dDistance;
x1
=
x1
-
x2;
y1
=
y1
-
y2;
dDistance
=
sqrt(x1
*
x1
+
y1
*
y1);
return
dDistance;
}
/
*
计算
3d
距离
*
/
float
Get3dDistance(Vector3 MyPos, Vector3 TargerPos,
int
Divide)
{
float
fDistance;
Vector3 vec;
vec.x
=
TargerPos.x
-
MyPos.x;
vec.y
=
TargerPos.y
-
MyPos.y;
vec.z
=
TargerPos.z
-
MyPos.z;
fDistance
=
sqrt(
pow
(vec.x,
2
)
+
pow
(vec.y,
2
)
+
pow
(vec.z,
2
));
return
fDistance
/
Divide;
}
/
*
读坐标
*
/
Vector3 ReadVector3(ULONG64 addr, DWORD
Type
)
{
return
ReadMem<Vector3>(addr
+
Type
);
}
/
*
3d
-
>
2d
*
/
DWORD g_dwWidth,g_dwHeight;
bool
WorldToScreen_2D(Matrix viewWorld, Vector3 TargerPos, Vector2
*
result)
{
float
fViewW
=
viewWorld._14
*
TargerPos.x
+
viewWorld._24
*
TargerPos.y
+
viewWorld._34
*
TargerPos.z
+
viewWorld._44;
if
(fViewW <
0.01f
) {
return
false; }
fViewW
=
1
/
fViewW;
float
fBoxX
=
g_dwWidth
/
2
+
(viewWorld._11
*
TargerPos.x
+
viewWorld._21
*
TargerPos.y
+
viewWorld._31
*
TargerPos.z
+
viewWorld._41)
*
fViewW
*
g_dwWidth
/
2
;
float
fBoxY
=
g_dwHeight
/
2
-
(viewWorld._12
*
TargerPos.x
+
viewWorld._22
*
TargerPos.y
+
viewWorld._32
*
TargerPos.z
+
viewWorld._42)
*
fViewW
*
g_dwHeight
/
2
;
result
-
>x
=
fBoxX;
result
-
>y
=
fBoxY;
return
true;
}
/
*
读矩阵
*
/
void GetMatrix(ULONG64 Addr, Matrix
*
ViewWorld)
{
*
ViewWorld
=
ReadMem<Matrix>(ReadMem<ULONG64>(ReadMem<ULONG64>(Addr)
+
0x20
)
+
0x270
);
}
int
toMove(
int
a)
{
a
=
fabs(a);
if
(a >
200
)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-4-26 19:04
被0x太上编辑
,原因: