郁金香2021年游戏辅助技术(初级班)(上)

%p、size_t、%zd、%llu、FindWindow、GetWindowText、SetWindowText

HMODULE hModule = GetModuleHandle(nullptr);
// %p 表示格式化指针
printf("ddd %p\n", hModule);
// sizeof输出的类型为size_t,%zd 表示格式化size_t类型大小
// 在x64系统下sizeof运算符 返回值是size_t 占用空间8字节 要使用%llu格式化输出
printf("sizeof(HMODULE)=%zd 字节\n", sizeof(hModule));	// sizeof(HMODULE)
//HWND hWnd = reinterpret_cast<HWND>(0x001A03DE);
printf("sizeof(DWORD)=%zd sizeof(LONG)=%zd\n", sizeof(DWORD), sizeof(LONG));

	// char short int的表示范围
	// 头文件 #include<limits.h>
	printf("char类型表示范围 %d至%d\r\n", SCHAR_MIN, SCHAR_MAX);
	printf("unsigned char类型表示范围 %u至%u\r\n", 0, UCHAR_MAX); 
	// short 
	printf("short类型表示范围 %d至%d\r\n", SHRT_MIN, SHRT_MAX);
	printf("unsigned short类型表示范围 %u至%u\r\n", 0, USHRT_MAX);
	// int  -21亿 +21亿
	printf("int类型表示范围 %d至%d\r\n", INT_MIN, INT_MAX);
	printf("unsigned int类型表示范围 %u至%u\r\n", 0, UINT_MAX);

HWND calcHwnd = FindWindow(L"CalcFrame", nullptr);
printf("窗口句柄=%p\r\n", calcHwnd);
TCHAR buf[MAX_PATH] = { 0 };
wchar_t outBuf[MAX_PATH] = { 0 };
GetWindowText(calcHwnd, buf, MAX_PATH);
// %ws 表示格式化宽字符串
swprintf_s(outBuf, L"calc %ws\n", buf);	
// 宽字符串也可以使用大写的%S格式化输出
//_stprintf_s(outBuf, _T("calc caption %S\n"), buf);
MessageBox(nullptr, outBuf, buf, MB_OK);
SetWindowText(calcHwnd, L"我的计算器zzz");

GetWindowThreadProcessId、OpenProcess、ReadProcessMemory

GetWindowThreadProcessId //返回线程TID和进程PID

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#include <iostream>	// 包含了<stdio.h>头文件
#include<Windows.h>
int main()
{
     // 1 通过窗口标题或者类名 获取目标窗口句柄
	 // 2 通过窗口句柄获取进程的PID,TID
	HWND 窗口句柄 = FindWindowA("MainWindow", "植物大战僵尸中文版");
	printf("窗口句柄 h=%p\r\n", h);
	DWORD pid = 0, tid = 0;
	printf("&pid=%p\r\n", &pid);
	// int 和 long是等价
	// DWORD  等价于 unsigned long 
	// DWORD* 等价于 LPDWORD
	tid = GetWindowThreadProcessId(窗口句柄, &pid);
	printf("tid=%d pid=%d  16进制tid=%X 16进制pid=%X\r\n", tid, pid, tid, pid);

	// 获取 进程 权限 句柄
	// 通过pid获取进程句柄,同时要指定渴望得到的访问权限
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); // PROCESS_VM_READ
	printf("进程句柄=%p \r\n", 进程句柄);
	unsigned int 返回值 = 0;
	//跨进程读取目标进程指定地址处的4字节数据
	//ReadProcessMemory(进程句柄, (LPCVOID)0x0000000077B2C934/*要读取的地址*/, &返回值/*存放数据的地址*/, 4, 0);
	ReadProcessMemory(进程句柄, reinterpret_cast<LPCVOID>(0x77B2C934)/*要读取的地址*/, &返回值/*存放数据的地址*/, 4, 0);
	printf("返回值=%X 返回值=%d 返回值=%u\r\n", 返回值, 返回值, 返回值);// GetLastError();
}

在这里插入图片描述


封接读内存接口函数 int R4(void* 地址)

通过接口函数读取基址偏移公式里的数据。

在这里插入图片描述

DWORD R4(UINT_PTR 内存地址)
{ 
	HWND 窗口句柄 = FindWindowA("MainWindow", "植物大战僵尸中文版"); 
	DWORD pid = 0, tid = 0;  
	tid = GetWindowThreadProcessId(窗口句柄, &pid);
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);	// PROCESS_VM_READ
	DWORD 返回值 = 0;
	ReadProcessMemory(进程句柄, (LPCVOID)内存地址/*要读取的地址*/, &返回值/*存放数据的地址*/, 4, 0);
	return 返回值;
}

跨进程向目标进程内存地址写入数值 WriteProcessMemory

在这里插入图片描述

#include <iostream>
#include<Windows.h>

HWND 获取游戏窗口句柄()
{
	return FindWindowA("MainWindow", "植物大战僵尸中文版");
}

//unsigned
DWORD R4(UINT_PTR 内存地址)
{
	HWND 窗口句柄 = 获取游戏窗口句柄();	//FindWindowA("MainWindow", "植物大战僵尸中文版");
	DWORD pid = 0, tid = 0;
	tid = GetWindowThreadProcessId(窗口句柄, &pid);
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	DWORD 返回值 = 0;
	ReadProcessMemory(进程句柄, (LPCVOID)内存地址/*要读取的地址*/, &返回值/*存放数据的地址*/, 4, nullptr);
	CloseHandle(进程句柄);//释放掉句柄资源
	return 返回值;
}

//写入成功 W4返回 非0的数值
//写入失败 W4返回 0
int W4(UINT_PTR 内存地址/*要写入目标进程的内存地址*/, DWORD 要写入的值)
{
	HWND 窗口句柄 = 获取游戏窗口句柄();	//FindWindowA("MainWindow", "植物大战僵尸中文版");
	DWORD pid = 0, tid = 0;
	tid = GetWindowThreadProcessId(窗口句柄, &pid); 
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	unsigned int 返回值 = WriteProcessMemory(进程句柄, (LPCVOID)内存地址/*要写的目标进程地址*/, &要写入的值/*存放待写入数据的地址*/, 4, nullptr);
	CloseHandle(进程句柄);//释放掉句柄资源
	return 返回值;
}

int main()
{
	//[[6A9EC0]+768]+5560 =14F2A3D8
	// [[[6A9EC0]+768]+5560]=75
	int 阳光 = R4(R4(R4(0x6A9EC0) + 0x768) + 0x5560);
	UINT_PTR 阳光地址 = R4(R4(0x6A9EC0) + 0x768) + 0x5560;
	printf("阳光=%d\r\n", 阳光);
	printf("阳光地址=%X\r\n", 阳光地址);
	
	W4(阳光地址, 567);
	
	getchar();//等待键盘输入
}

int main_0()
{
	//[[6A9EC0]+768]+5560 =14F2A3D8
	// [[[6A9EC0]+768]+5560]=75
	int 阳光 = R4(R4(R4(0x6A9EC0) + 0x768) + 0x5560);
	UINT_PTR 阳光地址 = R4(R4(0x6A9EC0) + 0x768) + 0x5560;
	printf("阳光=%d\r\n", 阳光);
	printf("阳光地址=%X\r\n", 阳光地址);

	HWND 窗口句柄 = 获取游戏窗口句柄();	//FindWindowA("MainWindow", "植物大战僵尸中文版");
	DWORD pid = 0, tid = 0;
	tid = GetWindowThreadProcessId(窗口句柄, &pid);
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	int 新阳光的值 = 66666;
	WriteProcessMemory(进程句柄, (LPVOID)阳光地址, &新阳光的值, 4, nullptr);
	CloseHandle(进程句柄);//释放掉句柄资源

	getchar();//等待键盘输入
}

C,C++32位和64位进程内存数据读写函数接口、通过头文件进行项目管理

在这里插入图片描述

// 内存读写.h
#pragma once
#include <iostream>
#include<Windows.h>

HWND 获取游戏窗口句柄();
DWORD R4(UINT_PTR 内存地址/*从这个地址开始读取4字节*/);
int W4(UINT_PTR 内存地址/*从这个地址开始写入4字节*/, DWORD 要写入的值);
// 内存读写.cpp
#include "内存读写.h"

HWND 获取游戏窗口句柄()
{
	return FindWindowA("MainWindow", "植物大战僵尸中文版");
}

// 读取4字节数据
DWORD R4(UINT_PTR 内存地址)
{
	HWND 窗口句柄 = 获取游戏窗口句柄();	//FindWindowA("MainWindow", "植物大战僵尸中文版");
	DWORD pid = 0, tid = 0;
	tid = GetWindowThreadProcessId(窗口句柄, &pid);
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	DWORD 返回值 = 0;
	ReadProcessMemory(进程句柄, (LPCVOID)内存地址/*要读取的地址*/, &返回值/*存放数据的地址*/, 4, nullptr);
	CloseHandle(进程句柄);//释放掉句柄资源
	return 返回值;
}

//写入成功 W4返回 非0的数值
//写入失败 W4返回 0
int W4(UINT_PTR 内存地址/*要写入目标进程的内存地址*/, DWORD 要写入的值)
{
	HWND 窗口句柄 = 获取游戏窗口句柄();	//FindWindowA("MainWindow", "植物大战僵尸中文版");
	DWORD pid = 0, tid = 0;
	tid = GetWindowThreadProcessId(窗口句柄, &pid); 
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	unsigned int 返回值 = WriteProcessMemory(进程句柄, (LPCVOID)内存地址/*要写的目标进程地址*/, &要写入的值/*存放待写入数据的地址*/, 4, nullptr);
	CloseHandle(进程句柄);//释放掉句柄资源
	return 返回值;
}
// main程序入口点.cpp
#include "内存读写.h"

	//[[6A9EC0]+768]+5560 =14F2A3D8
	// [[[6A9EC0]+768]+5560]=75
	int 阳光 = R4(R4(R4(0x6A9EC0) + 0x768) + 0x5560);
	UINT_PTR 阳光地址 = R4(R4(0x6A9EC0) + 0x768) + 0x5560;
	printf("阳光=%d\r\n", 阳光);
	printf("阳光地址=%X\r\n", 阳光地址);
	
	DWORD 新的阳光值 = 5567;
	W4(阳光地址, 新的阳光值);
	
	getchar();//等待键盘输入

X64环境masm汇编asm文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

当我们在x32dbg调试器中找不到main入口点的时候,可以通过在main函数主体最开始位置那里,添加MessageBoxA或者MessageBeep函数这种方法来定位入口点:

在这里插入图片描述

在这里插入图片描述

如上图所示,通过跳转到MessageBoxA函数这里并下断点,运行到这里断下后,在右下角栈那里可以看到_main返回地址。

在我们自己编写代码调试测试的时候,最好把随机基址给禁用掉,这样就可以变成固定地址,方便我们测试:

在这里插入图片描述

  call指令
  77256C78 | E8 EF02FBFF    | call ntdll.77206F6C       
  EIP=77206F6C
  push 77256C78+5 //esp=esp-4	//64 rsp=rsp-8
  
  ret指令
  77256CAF | C3             | ret    
  跳转到 [esp]
  esp=esp+4  //64 rsp=rsp+8

常见的六种参数调用约定传递与平栈

在这里插入图片描述


x86环境

#include<iostream>

//VS环境默认的调用约定
//add esp,参数数量*4
//add rsp,参数数量*8
int _cdecl call_cdecl(int a, int b)
{
	return a + b;
}

//ret 参数数量*4  //x86   //ret 8
//ret 参数数量*8  //x64   //ret 10
int _stdcall call_std(int a, int b)
{
	return a + b;
}
//快速
int _fastcall call_fast(int a, int b)
{
	return a + b;
}
// thiscall 类成员函数独有
/*
int __thiscall call_vector(int a, int b)
{
	return a + b;
}
*/
// __vectorcall (/ Gv)
int __vectorcall call_vector(int a, int b)
{
	return a + b;
}

//int __clrcall test()
//{
//	return 1;
//}

int abc(int a, int b, int c)
{
	printf("技能释放 a=%d,b=%d c=%d\r\n", a, b, c);
	return a + b + c;
}
int main()
{
	int a = 333;
	int b = 123;
	printf(" call_cdecl()=%X行号=%d\r\n",  call_cdecl(0x11A, 0xA11), __LINE__);

	printf(" call_std()=%X行号=%d\r\n",    call_std(0x11B, 0xB11), __LINE__);

	printf(" call_fast()=%X行号=%d\r\n",   call_fast(0x11C, 0xC11), __LINE__);

	printf(" call_vector()=%X行号=%d\r\n", call_vector(0x11D, 0xD11), __LINE__);

	printf(" 释放技能 abc=%d\r\n", abc(0x123, 2, 6));
	getchar();
	return 1;
}

在这里插入图片描述

在这里插入图片描述

可以按冒号给函数添加标签,按分号添加注释。

在这里插入图片描述

在x86环境下,_fastcall调用约定,传递参数:ecx参数1、edx参数2、剩下的参数通过堆栈(push)来传递,并在函数内进行平栈(ret n)。

在这里插入图片描述

在x86环境下,_vectorcall调用约定,传递参数:ecx参数1、edx参数2、剩下的参数通过堆栈(push)来传递,也是在函数内进行平栈(ret 数值)。
由于现在传的参数都是整数,所以_fastcall和_vectorcall我们通过反汇编看到参数传递、堆栈平衡都一样;其实它们是有区别的,区别应该就在于参数是浮点数的情况下。

在x86环境下,_cdecl和_stacall调用约定,全部是用push传递参数。


x64环境

#include<iostream>

//VS环境默认的调用约定
//add esp,参数数量*4
//add rsp,参数数量*8
int _cdecl call_cdecl(int a, int b,int a3,int a4,int a5,int a6)
{
	return a + b+a3+a4+a5+a6;
}

//ret 参数数量*4  //x86   //ret 8
//ret 参数数量*8  //x64   //ret 10
int _stdcall call_std(int a, int b, int a3, int a4, int a5, int a6)
{
	return a + b + a3 + a4 + a5 + a6;
}
//快速
int _fastcall call_fast(int a, int b, int a3, int a4, int a5, int a6)
{
	return a + b + a3 + a4 + a5 + a6;
}
// thiscall 类成员函数独有
/*
int __thiscall call_vector(int a, int b)
{
	return a + b;
}
*/
// __vectorcall (/ Gv)
int __vectorcall call_vector(int a, int b, int a3, int a4, int a5, int a6)
{
	return a + b + a3 + a4 + a5 + a6;
}

//int __clrcall test()
//{
//	return 1;
//}

int abc(int a, int b, int c)
{
	printf("技能释放 a=%d,b=%d c=%d\r\n", a, b, c);
	return a + b + c;
}
int main()
{
	int a = 333;
	int b = 123;
	printf(" call_cdecl()=%X行号=%d\r\n", call_cdecl(0x11A, 0xA11,3,4,5,6), __LINE__);

	printf(" call_std()=%X行号=%d\r\n", call_std(0x11B, 0xB11,3,4,5,6), __LINE__);

	printf(" call_fast()=%X行号=%d\r\n", call_fast(0x11C, 0xC11,3,4,5,6), __LINE__);

	printf(" call_vector()=%X行号=%d\r\n", call_vector(0x11D, 0xD11,3,4,5,6), __LINE__);

	printf(" 释放技能 abc=%d\r\n", abc(0x123, 2, 6));
	getchar();
	return 1;
}

在x64dbg调试器中,转到main函数的话,ctrl+G,输入main确定即可,main前面不需要加下划线(x86)。

在这里插入图片描述

在x64环境下,_cdecl、_stacall和_fastcall、_vectorcall这4种调用约定,我们发现都一样,都是用rcx、rdx、r8、r9来传递参数,超出4个的参数用堆栈(rsp+20)来传递。

我们看到第5个参数是rsp+20,前4个参数占0x20大小的空间,但是在x64环境下,前4个参数分别通过rcx、rdx、r8、r9来传递,为了对齐(也是为了兼容x86汇编),第5个参数通过rsp+20来传递,第6个参数通过rsp+28来传递;
而且在函数内部最后一条指令就是一条ret,后面不跟数值。

经过测试我们发现,在x64环境下,这4种调用约定是没有区别的,参数传递和平栈方式都是相同的,所以暂时可以认为这4种调用约定是相同的。

在这里插入图片描述

由于call该函数的指令执行后,rsp=rsp-8,所以上图mov ss:[rsp+20],r9d并没有覆盖call指令执行前的第5个参数,mov ss:[rsp+20],r9d对于call指令执行前的环境来说,相当于mov ss:[rsp+18],r9d,即第4个参数给了ss:[rsp+18],在函数里面的这种堆栈传参方式也是为了兼容x86汇编。
即堆栈变化示意图如下:

在这里插入图片描述

在这里插入图片描述

x64寄存器低4字节低2字节低1字节
rcxecxcxcl
rdxedxdxdl
r8r8dr8wr8b
r9r9dr9wr9b

再看一个函数,堆栈变化同理:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以针对所有配置、所有平台进行设置:

在这里插入图片描述


汇编条件转移指令与循环

在这里插入图片描述

在这里插入图片描述

int main_while01()
{
	/* 局部变量定义 */
	int a = 10;

	/* while 循环执行 */
	// SF(符号标志位)
	// OF(溢出标志位)
	//cmp a-20 从而影响到 符号标志位
	while (a < 20) // SF=OF  
	{
		printf("a 的值: %d  行号=%d \n", a, __LINE__);
		a++; //a=a+1; add [esp+??],1// inc [esp+??]
	}
	return 0;
}

int main()
{
	printf("main start 行号=%d \n", __LINE__);
	main_while01();
	printf("main end   行号=%d \n", __LINE__);
	return 1;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们看到上图OF不等于SF,SF为1,这是有符号跳转指令JL的条件,所以jge条件不成立,不跳转,进入循环。
(汇编指令cmp就是做了一个减法操作,即a - 20,从而影响到符号标志位SF)

在这里插入图片描述

如上图所示,当ss:[ebp-8]等于14的时候,执行cmp指令,可以看到ZF等于1,OF等于SF都为0:

在这里插入图片描述

当OF等于0,SF等于0,即OF==SF,那么有符号跳转指令jge跳转条件成立,循环终止。

减法的话对SF和ZF标志位有影响;
加法的话对CF和OF标志位有影响。

我们再来看看包含continue语句的while循环代码:

int main_continue()
{
	/* 局部变量定义 */
	int a = 0;

	/* while 循环执行 */
	while (a < 10) //0x0A=10
	{
		a++;
		if (a == 5)
		{
			/* 使用 continue 进入下一次循环 */
			continue;
		}
		printf("for循环测试:a 的值: %d 行号=%d \n", a, __LINE__);
	}
	return 0;
}

int main()
{
	printf("main start 行号=%d \n", __LINE__);
	main_continue();
	printf("main end   行号=%d \n", __LINE__);
	return 1;
}

在这里插入图片描述

我们从上图可以看到,判断小于的话用jge指令,判断等于的话用jne指令。


C,C++用代码,跨进程调用CALL

用代码注入器调用CALL

#include <iostream>
#include <Windows.h>
int call00()
{
	printf("call00 无参数 call0_test  行号=%d\r\n",  __LINE__);
	return 0x123;
}

int call01(int a)
{
	printf("call01 参数1=%d   行号=%d\r\n", a,  __LINE__);
	return a + 2;
}

int call02(int a, int b)
{
	printf("call02 参数1=%d 参数2=%d 行号=%d\r\n", a, b,__LINE__);
	return a + b+3;
}

int main()
{
//	MessageBoxA(0, 0, 0, 0);//ctrl+G 转到 MessageBoxA 下断
	printf("MessageBoxA=%p 行号=%d \r\n", MessageBoxA, __LINE__);
	int 计数 = 1;
	while (1)
	{
		printf("call00=%p call01=%p,call02=%p \n", call00, call01, call02);
		getchar();
		printf("计数=%d,行号=%d \r\n", 计数++, __LINE__);
	}
	return 1;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注意,x64dbg标题栏上的线程号5236是十进制的,左下角的1474是十六进制的,这两个数是一样的


C,C++创建远程线程调用CALL

  • 远程调用CALL的流程
    1. 用spy++获取目标窗口句柄,FindWindow
    2. 有了窗口句柄的情况 用GetWindowThreadProcessID获取目标进程PID
    3. 通过OpenProcess获取目标进程的线程创建权限 获取相应的句柄
    4. 用CreateRemoteThread调用远程的CALL
#include <iostream>
#include<Windows.h>
//unsigned
//int R4(UINT_PTR 内存地址)
//{
//	HWND 窗口句柄 = FindWindowA("MainWindow", "植物大战僵尸中文版");
//	DWORD pid = 0, tid = 0;
//	tid = GetWindowThreadProcessId(窗口句柄, &pid); // a&b 
//	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);//HWND
//	unsigned int 返回值 = 0;
//	ReadProcessMemory(进程句柄, (LPCVOID)内存地址/*要读取的地址*/, &返回值/*存放数据的地址*/, 4, 0);
//	return 返回值;
//}

// \n
// \ \\
// 窗口标题= "C:\\Users\\Administrator\\source\\repos\\A001\\Debug\\A023_测试CALL.exe"
//#define 窗口标题 "C:/moshou/A001-游戏辅助技术(初级班)/代码\A001-024/Debug"
//#define 窗口标题 "C:\moshou\A001-游戏辅助技术(初级班)\代码\A001-024\Debug"
#define 窗口标题 R"(C:\moshou\A001-游戏辅助技术(初级班)\代码\A001-024\Debug\A023_测试CALL.exe)"

DWORD 获取PID()
{
 	HWND 窗口句柄 = FindWindowA(0, 窗口标题);
 	DWORD pid = 0, tid = 0;
 	tid = GetWindowThreadProcessId(窗口句柄, &pid); // a&b 
	return pid;
}

void 调用call01测试()
{
	DWORD pid = 4180; //直接在任务管理器里 取得PID
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);//HWND
	//1,4,5 重视这3个参数
	CreateRemoteThread(
		进程句柄,//1
		0, //2
		0, //3
		(LPTHREAD_START_ROUTINE)0x411370,//4 CALL地址
		(LPVOID)123,//5 CALL的参数
		0,
		0);
}

void 调用call01测试2(int 参数1)
{
	DWORD pid = 4180;//任务管理器取的pid
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);//HWND
	//1,4,5 重视这3个参数
	CreateRemoteThread(
		进程句柄,//1
		0, //2
		0, //3
		(LPTHREAD_START_ROUTINE)0x411370,//4 CALL地址
		(LPVOID)参数1,//5 CALL的参数
		0,
		0);
	CloseHandle(进程句柄);
}

void 调用call01测试3(int 参数1)
{
	DWORD pid = 获取PID();//任务管理器取的pid
	printf("pid=%d \r\n", pid);
	HANDLE 进程句柄 = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);//HWND
	//1,4,5 重视这3个参数
	CreateRemoteThread(
		进程句柄,//1
		0, //2
		0, //3
		(LPTHREAD_START_ROUTINE)0x4113CA,//4 call01地址
		(LPVOID)参数1,//5 CALL的参数
		0,
		0);
	CloseHandle(进程句柄);
}

int main()
{
	调用call01测试3(12666);
	调用call01测试3(12667);
	调用call01测试3(12668);
	//R忽略 转义字符
	char test[]= R"(C:\Users\Administrator\source\repos\A001\Debug\A023_测试CALL.exe)";
	//char test2[] = "C:\Users\Administrator\source\repos\A001\Debug\A023_测试CALL.exe";
	printf("%s\r\n",test);
    std::cout << "Hello World!\n";
}
 

杂项

常用软件游戏

在这里插入图片描述

这个代码注入器只能用于32位程序的测试,64位进程能用的这类代码注入工具目前还没有发现免费的,我们只能自己写代码来注入。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

免签名加载驱动:
https://github.com/TheCruZ/kdmapper

win10过签名:
https://github.com/HyperSine/Windows10-CustomKernelSigners

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
vs平台工具集如果装了Inter C++ Compiler编译器的话,Intel的编译器是支持__asm int 3这些内联汇编的:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


定位特征码

在这里插入图片描述
编辑好特征码之后,移动到函数开头、或者更上面一些,Ctrl+B打开输入要查找的二进制字串对话框,粘贴特征码搜索,能找到的话说明我们编写的特征码没问题;
还应该重启游戏,打开OD附加游戏,按照上面所述搜索特征码进行验证。


d3d8thk劫持注入

在这里插入图片描述

在这里插入图片描述


PE查看分析工具

PE查看器(PE_Study) https://www.cr173.com/soft/47081.html
PE文件查看器(PETool) https://www.cr173.com/soft/89855.html
逆缘PE文件提取 https://www.cr173.com/soft/85171.html

PE分析工具(PE_Hacker) https://www.cr173.com/soft/1438600.html
https://blog.csdn.net/PE_Hacker/article/details/115766034

PE-Analysis:

在这里插入图片描述


驱动开发调试工具 DriverTool

驱动开发调试工具,比如测试模式下的数字签名Windows 64Signer V1.2,又比如DebugView等一些工具。

在这里插入图片描述

/

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
免key版,511U盘资源,速度很快!经测试全部可下 课程分四个大章节 初级篇,中级篇,进阶篇,高级篇 初级篇内容:编写一个完整的,简单的外挂 C++的数据类型:Byte,Word,DWORD,int,float API函数的调mouse_event,GetWindowRect,SetCursorPos,FindWindow,SendMessage) CE5.4工具的使用方法 中级篇内容:调试工具的使用技巧,功能CALL的概念 调试工具OD1.1的使用技巧(如硬件断点,条件断点,内存断点。 常用汇编指令与对应高级语言的转换。 游戏功能CALL概念 找第一个功能CALL 外挂框架的构建(通用) 进阶篇内容:分析游戏内部数据,分析常用功能CALL 游戏数据实践找各种功能CALL(如打怪,选怪,物品使用,技能栏之类)及相应的代码编写 高级篇内容:编写完整外挂 完成一个相对完整的外挂,实现 自动挂机,打怪,存放物品之类的功能 1 入门篇.以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最简单的外挂(实现游戏开局) a、鼠拟鼠标单击mouse_event b、鼠标指针移动还原 c、集成到startgame函数里 1.2、用CE查找棋盘数据 1.2.1、CE中的数据类型 a、数据类型:Bit,Byte,Word,Dword,float,double b、用CE查找出坐位号; c、保存分析数据 1.2.2、编程读出坐位号; a、远程读取进程数据 b、打开远程进程 c、读取远程进程数据 1.2.3、用CE查出棋盘基址; a、找棋盘数据基址 b、分析棋盘数据结构 1.2.4、读出当前棋盘数据 a、编程读出棋盘数据 b、棋盘数据显示出来 1.3、用模拟技术编制外挂 1.3.1 分析棋子与棋盘坐标关系 a、鼠标软件模拟,函数SendMessage b、分析窗口内棋子相对坐标X,Y c、软件模拟点击棋盘坐标x,y处的棋子 1.3.2 消掉一对棋子的算法框架 a、遍历棋盘同类型棋子配对 b、构建算法框架 1.3.3 (Check2p)大致框架(算法核心) a、在这一对棋子间找相通路径的原理 b、(Check2p函数)框架代码 c、(CheckLine函数)检测2点是否有连通. 1.3.4 CheckLine实现 a、CheckLine函数实现 b、Check2p核心代码架构 1.3.5 Check2p完整代码实现 1.3.6 编写完整外挂,界面美化 1.4、游戏加速.去掉对动画效果.非HOOK 1.4.1:用OD找出 动画延时代码 1.4.2:写代码去掉延时,实现游戏加速 2 中级篇 以热血江湖为例 2.1、分析前的准备..CALL简介: 2.1.1、CALL调用示例分析.
课程安排,暂定,有可能会实时修改 编程语言,VC++6.0 工具主要为(OD1.1,CE5.4) 预计平均3天左右更新一课 大家好,我是郁金香老师:QQ150330575 欢迎大家参加梅州技术 VC++外挂编程VIP培训。 在接下来的一段时间将由我和大家一起学习游戏外挂的分析,制作。 课程分四个大章节 初级篇,中级篇,进阶篇,高级篇 初级篇内容:编写一个完整的,简单的外挂 C++的数据类型:Byte,Word,DWORD,int,float API函数的调mouse_event,GetWindowRect,SetCursorPos,FindWindow,SendMessage) CE5.4工具的使用方法 中级篇内容:调试工具的使用技巧,功能CALL的概念 调试工具OD1.1的使用技巧(如硬件断点,条件断点,内存断点。 常用汇编指令与对应高级语言的转换。 游戏功能CALL概念 找第一个功能CALL 外挂框架的构建(通用) 进阶篇内容:分析游戏内部数据,分析常用功能CALL 游戏数据实践找各种功能CALL(如打怪,选怪,物品使用,技能栏之类)及相应的代码编写 高级篇内容:编写完整外挂 完成一个相对完整的外挂,实现 自动挂机,打怪,存放物品之类的功能 1 入门篇.以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏数据分析(SPY++) 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最简单的外挂(实现游戏开局) a、鼠拟鼠标单击mouse_event b、鼠标指针移动还原 c、集成到startgame函数里 1.2、用CE查找棋盘数据 1.2.1、数据类型:Bit,Byte,Word,Dword 、用CE查找坐位号; 1.2.2、用CE查出4个棋盘基址; 1.3、用模拟技术编制外挂 1.3.1 模拟鼠标点击实现 交换棋子 1.3.2 把所有功能集成封装到 函数里 1.3.3 利用棋盘数据 ,模拟实现下棋功能 1.3.4 编写完整外挂,界面美化 1.4、游戏加速.去掉对动画效果.非HOOK 1.4.1:用OD找出 动画延时代码 1.4.2:写代码去掉延时,实现游戏加速 2 中级篇 以热血江湖为例 2.1、分析前的准备..CALL简介: 2.1.1、CALL调用示例分析.远程代码注入器 2.1.2、调试工具OD简介,血值,魔力值,坐标偏移; 2.1.3、游戏基址概念; 2.1.4、常用汇编指令详解 2.1.5、内联汇编编程实例 2.2、游戏分析利器OD(OllyDbg) 2.2.1、分析角色基址 2.2.2、找打坐CALL 2.2.3、读出角色当前血值 2.2.4、远程注入代码,调用打坐CALL; 2.2.5、实例分析:找技能栏对象数组基址+偏移: 2.2.6: 拦截F1-F8功能CALL 2.3、外挂框架构建 2.3.1、DLL动态链接库构建,与调用 2.3.2、API与回调函数 2.3.3、DLL中构建窗口 2.4、用OD分析游戏功能CALL.《热血江湖》为例:主要是找CALL 2.4.1、选怪CALL 2.4.2、找游戏物品背包的基址+偏移 2.4.3、 吃红药(补血)CALL 2.4.4、 吃蓝(补魔)CALL 2.4.5、 技能CALL1 2.4.6、技能CALL2 2.4.7、所有技能CALL 2.4.8、捡物CALL 2.4.9、所有动作CALL 3、进阶篇 主要讲功能CALL的参数分析 汇编浮点指令/浮点运行/浮点数整数转换/汇编里的指针 3.1、喊话功能 3.2、走路 3.3、 怪物过滤 3.3.1、怪物属性分析 3.3.2、怪物列表关键代码分析 3.3.3、怪物列表基址+大小 3.3.4、怪物列表编写代码 3.3.5、怪物过滤 3.4、 物品过滤 3.4.1、物品属性分析 3.4.2、物品列表关键代码分析 3.4.3、找出物品列表基址+偏移 3.4.4、物品过滤(编程读出物品列表数据) 3.5、 组队相关 3.5.1、 玩家列表 3.5.2、 组队功能 3.5.3、 离队功能 3.6、购物/售物 3.6.1、与NPC对话框 3.6.2、打开购物/售物对话框 3.6.3、购物功能 3.6.4、售物功能 3.7、 摆摊.开店 a、开店CALL参数分析 b、写代码测试 4、高级篇 4.1、编写完整的外挂 4.2、游戏更新后的外挂更新 4.3、脚本功能 4.4、游戏多开实现 4.5、盗号的实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值