郁金香2021课程
2025年4月3日
01-函数入口
#include <stdio.h>
void main() {
printf("我的第一个程序");
// 等待键盘输入
getchar();
}
02-函数和转义字符
#include <stdio.h>
void func() {
printf("自定义函数\n");
}
int main() {
func();
// \n换行
printf("我的第一个程序\n");
// 等待键盘输入
getchar();
return 0;
}
03-调用window系统api
#include <iostream>
#include <Windows.h>
int main()
{
MessageBoxA(0, "我的内容", "标题", 1);
/* MessageBoxA(
_In_opt_ HWND hWnd, 窗口句柄
_In_opt_ LPCSTR lpText, 内容
_In_opt_ LPCSTR lpCaption, 标题
_In_ UINT uType); 按钮类型
*/
}
04-数据类型
#include <iostream>
#include <limits.h>
int main()
{
//char 1字节 能表示256个整数 -127到128
// unsigned char 也是能表示256个,但是是0到256
char a = 'a';
char b = 'b';
// %zd是大于0的 %d带符号整数 %u无符号整数 %llu 无符号整数(8字节)
printf("char变量所占内存空间:%d,%zd", sizeof(a), sizeof(b));
printf("\n===============================================\n");
char c = 123;
char d = -123;
char e = 3333;
// 打印结果e=5 因为存不下,被截取了
printf("c = %d, d = %d, e = %d",c,d,e);
printf("\n===============================================\n");
// short为2字节
short i, j, k;
i = 3333;
j = -3333;
k = 33336;
// k被截取
printf("i = %d, j = %d, k = %d", i, j, k);
printf("\n===============================================\n");
// int为4字节
int a1, a2;
a1 = 33336;
a2 = -33336;
// 正常显示
printf("a1 = %d, a2 = %d", a1, a2 );
printf("\n===============================================\n");
// 范围在limits.h中有定义常量,可以打印出来看看
printf("char可以表示的范围是:%d到%d\n", SCHAR_MIN, SCHAR_MAX);
printf("unsigned char可以表示的范围是:%d到%d\n", 0, UCHAR_MAX);
printf("short可以表示的范围是:%d到%d\n", SHRT_MIN, SHRT_MAX);
printf("unsigned short可以表示的范围是:%d到%d\n", 0, USHRT_MAX);
printf("int可以表示的范围是:%d到%d\n", INT_MIN, INT_MAX);
printf("unsigned int可以表示的范围是:%d到%d\n", 0, UINT_MAX);
return 0;
}
05-window api操作窗口
vscode工具中的spy++可以获取窗口标题、类名和句柄
#include <iostream>
#include <Windows.h>
int main()
{
// HWND为指针类型
HWND hwd = (HWND)FindWindowA("ConsoleWindowClass",NULL); //0x00261394;
printf("%p\r\n", hwd);
// 改变标题
SetWindowTextA(hwd,"新标题");
// eax是4字节,rax是8字节
printf("窗口句柄占字节数:%zd", sizeof(hwd));
return 0;
}
06-利用window api获取pid
#include <iostream>
#include <Windows.h>
int main()
{
// 获取窗口句柄
HWND hwd = (HWND)FindWindowA("MainWindow", "植物大战僵尸中文版");
printf("%p\r\n", hwd);
/*
GetWindowThreadProcessId(
_In_ HWND hWnd, // 窗口句柄
_Out_opt_ LPDWORD lpdwProcessId); // 变量,函数内会通过指针修改内存值
*/
DWORD pid,tid;
tid = GetWindowThreadProcessId(hwd, &pid);
printf("pid = %d,tid = %d", pid,tid);
getchar();
}
07-读取目标进程内存数据
#include <iostream>
#include <Windows.h>
int main()
{
// 获取窗口句柄
HWND hwd = (HWND)FindWindowA("MainWindow", "植物大战僵尸中文版");
printf("%p\r\n", hwd);
DWORD pid, tid;
tid = GetWindowThreadProcessId(hwd, &pid);
printf("pid = %d,tid = %d\r\n", pid, tid);
// 操作进程需要获取进程句柄
/*
OpenProcess(
_In_ DWORD dwDesiredAccess, 渴望得到的权限
_In_ BOOL bInheritHandle, 是否继承句柄
_In_ DWORD dwProcessId 进程pid
);
*/
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
printf("进程句柄:%d\r\n", h);
/*
ReadProcessMemory(
_In_ HANDLE hProcess, 进程句柄
_In_ LPCVOID lpBaseAddress, 目标进程中的内存起始地址
_Out_writes_bytes_to_(nSize,*lpNumberOfBytesRead) LPVOID lpBuffer,用于存放数据的地址,先传入后,会被修改
_In_ SIZE_T nSize, 读取的字节数
_Out_opt_ SIZE_T* lpNumberOfBytesRead 返回的实际读取字节数
);
*/
unsigned int data;
ReadProcessMemory(h, (LPCVOID)0x77961000, &data, 4, 0);
printf("读取到的值:%x", data);
getchar();
}
08-封装读取4字节
#include <iostream>
#include <Windows.h>
unsigned int r4(UINT_PTR addr)
{
HWND hwd = (HWND)FindWindowA("MainWindow", "植物大战僵尸中文版");
DWORD pid, tid;
tid = GetWindowThreadProcessId(hwd, &pid);
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
unsigned int data;
ReadProcessMemory(h, (LPCVOID)addr, &data, 4, 0);
return data;
}
int main() {
unsigned int sun = r4(r4(r4(0x6a9ec0) + 0x768) + 0x5560);
printf("阳光值:%d", sun);
return 0;
}
09-CE分析基址偏移-精确数值
通过搜索找到记录,添加:
按快捷键f5找出是什么访问了这个地址,可能会有多条:
复制下来:
0041BAAF - CC - int 3
0041BAB0 - E8 CBFEFFFF - call PlantsVsZombie.exe+1B980
0041BAB5 - 03 82 60550000 - add eax,[edx+00005560] <<
0041BABB - 39 44 24 04 - cmp [esp+04],eax
0041BABF - 0F9E C0 - setle al
EAX=00000032
EBX=00000001
ECX=FFFFFFFF
EDX=1D98D050
ESI=000000FF
EDI=027B9D40
ESP=001996D8
EBP=1B01C970
EIP=0041BABB
0048981D - 84 C0 - test al,al
0048981F - 0F85 0E010000 - jne PlantsVsZombie.exe+89933
00489825 - 8B 86 60550000 - mov eax,[esi+00005560] <<
0048982B - 33 C9 - xor ecx,ecx
0048982D - 85 C0 - test eax,eax
EAX=00000032
EBX=00000002
ECX=00000000
EDX=0C8B4178
ESI=1D98D050
EDI=1B01C948
ESP=00199790
EBP=0019FA98
EIP=0048982B
可以先尝试从mov指令的这一条分析,mov eax,[esi+00005560]
,去搜索esi的值(1D98D050),把红色的过滤掉,多搜几次,会有很多条:
随便找一条,f5继续看是什么访问了(截图是找对了的,实际需要多次尝试):
继续f5:
随便找一条,看看:
再去搜eax的值:
出现了绿色的,就可以找到基址了,随便取一条都是基址。
10-CE分析基址偏移-未知初始值
11111
Loading...