其他
腾讯游戏安全大赛初赛题解
本文为看雪论坛精华文章
看雪论坛作者ID:xi@0ji233
找到明文
1.在64位Windows10系统上运行contest.exe, 找到明文的信息,作为答案提交(1分)。
catchmeifyoucan
ImVkImx9JG12OGtlImV+
。catchmeifyoucan
不确定它是不是flag,还得进一步确定,于是查找是谁访问了这个地址。r10
所指示的内存的操作。7FF713657190
地址,结果找到一串 base 表:QRSTUVWXYZabcdefABCDEFGHIJKLMNOPwxyz0123456789+/ghijklmnopqrstuv
写入明文信息
2.编写程序,运行时修改尽量少的contest.exe内存,让contest.exe 由写入密文信息变为写入明文信息成功。(满分2分)
and 0x3f
就是取得最低的六位,很明显是最后一位,同样也把中间的指令全部NOP掉。add r14,0
add r14,0
VirtualProtect
一直调用失败,拿火绒剑扫了一下,发现VirtualProtect
被下了钩子。思路讲解
VirtualProtectEx
先修改内存权限,再通过WriteProcessMemory
函数修复程序在API
处下的一个钩子,这里是inline hook
,因此直接遍历模块寻找ZwProtectVirtualMemory
函数把钩子取消。LoadLibraryA
函数去加载 DLL。注入器
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<TlHelp32.h>
DWORD old;
SIZE_T written;
DWORD FindProcess() {
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe32;
pe32 = { sizeof(pe32) };
BOOL ret = Process32First(hSnap, &pe32);
while (ret)
{
if (!wcsncmp(pe32.szExeFile, L"contest.exe", 11)) {
printf("Find contest.exe Process %d\n", pe32.th32ProcessID);
return pe32.th32ProcessID;
}
ret = Process32Next(hSnap, &pe32);
}
return 0;
}
void InjectModule(DWORD ProcessId, const char* szPath)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
printf("进程句柄:%p\n", hProcess);
LPVOID lpAddress = VirtualAllocEx(hProcess, NULL, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
SIZE_T dwWriteLength = 0;
WriteProcessMemory(hProcess, lpAddress, szPath, strlen(szPath), &dwWriteLength);
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, lpAddress, NULL, NULL);
WaitForSingleObject(hThread, -1);
VirtualFreeEx(hProcess, lpAddress, 0, MEM_RELEASE);
CloseHandle(hProcess);
CloseHandle(hThread);
}
void UNHOOK(DWORD ProcessId) {
BYTE INS[] = {0x4C,0x8B,0xD1,0xB8,0x50};
HANDLE ths = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
MODULEENTRY32 me;
me.dwSize = sizeof(me);
UINT64 addr=0;
if (Module32First(ths, &me))
{
do
{
if (addr=(UINT64)GetProcAddress(me.hModule, "ZwProtectVirtualMemory"))
{
printf("addr:%p\n", addr);
break;
}
} while (Module32Next(ths, &me));
}
CloseHandle(ths);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
VirtualProtectEx(hProcess, (void *)addr, 0x5, PAGE_EXECUTE_READWRITE, &old);
WriteProcessMemory(hProcess, (void *)addr, INS, 0x5, &written);
printf("written:%d\n", written);
VirtualProtectEx(hProcess, (void*)addr, 0x5, old, &old);
CloseHandle(hProcess);
}
int main() {
DWORD ProcessId = FindProcess();
while (!ProcessId) {
printf("未找到contest程序,等待两秒中再试\n");
Sleep(2000);
ProcessId = FindProcess();
}
printf("尝试去除钩子...\n");
UNHOOK(ProcessId);//去除钩子
printf("开始注入进程...\n");
InjectModule(ProcessId, "C:\\Users\\xia0ji233\\source\\repos\\T-contest\\x64\\Debug\\T-contest.dll");
printf("注入完毕\n");
}
dll
#include<time.h>
#include<stdio.h>
DWORD oldprot,ret;
PROC HookedFunction;
UINT64 Offset[3] = { 0xBA39 ,0xB9FD ,0xBA5D }, Len[3] = { 9,8,12 };//PATCH偏移和PATCH长度,这里皆patch为0x90(NOP)
BYTE Ins[] = {
0x41,0x88,0x06, //mov [r14],al
0x90, //nop
0x49,0x83,0xC6,0x00 //add r14, 0
};
UINT64 InsOffset = 0xBA05,InsLen=sizeof(Ins);
SIZE_T num;
BYTE buf = 0x90;
BYTE NOP[] = { 0x90,0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
void patch() {
UINT64 Base = (UINT64)GetModuleHandle(nullptr);
for (int i = 0; i < 3; i++) {
UINT64 addr = Base + Offset[i];
VirtualProtect((void *)addr, Len[i], PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)addr, NOP, Len[i]);
VirtualProtect((void*)addr, Len[i], oldprot, &oldprot);
}
printf("NOP done\n");
VirtualProtect((void*)(Base + InsOffset), InsLen,PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)(Base + InsOffset), Ins, InsLen);
VirtualProtect((void*)(Base + InsOffset), InsLen, oldprot, &oldprot);
printf("Instruction Patch Done!\n");
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
patch();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
更改写入文件
contest.txt
,于是尝试直接修改,发现可以成功更改写入的文件,因此为了达到目的我们可以直接修改这里的内存,但是因为它一直在变化,因此可以查看什么写了这个内存。#include<time.h>
#include<stdio.h>
DWORD oldprot,ret;
PROC HookedFunction;
UINT64 Offset[3] = { 0xBA39 ,0xB9FD ,0xBA5D }, Len[3] = { 9,8,12 };//PATCH偏移和PATCH长度,这里皆patch为0x90(NOP)
BYTE Ins[] = {
0x41,0x88,0x06, //mov [r14],al
0x90, //nop
0x49,0x83,0xC6,0x00 //add r14, 0
};
UINT64 InsOffset = 0xBA05,InsLen=sizeof(Ins);
SIZE_T num;
BYTE buf = 0x90;
BYTE NOP[] = { 0x90,0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
void patch() {
UINT64 Base = (UINT64)GetModuleHandle(nullptr);
for (int i = 0; i < 3; i++) {//把三个点位的指令NOP掉
UINT64 addr = Base + Offset[i];
VirtualProtect((void *)addr, Len[i], PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)addr, NOP, Len[i]);
VirtualProtect((void*)addr, Len[i], oldprot, &oldprot);
}
printf("NOP done\n");
VirtualProtect((void*)(Base + InsOffset), InsLen,PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)(Base + InsOffset), Ins, InsLen);//替换对应的指令
VirtualProtect((void*)(Base + InsOffset), InsLen, oldprot, &oldprot);
printf("Instruction Patch Done!\n");
}
void patchname() {
UINT64 Base = (UINT64)GetModuleHandle(nullptr);
UINT64 Offset1 = 0xC8F3,Offset2=0xC5C6,NameOffset=0x772FA,Len1=4,Len2=5,flagOffset = 0x772E9;
char NewName[] = "test.txt";//新文件名
char flag[] = "catchmeifyoucan";
VirtualProtect((void*)(Base + Offset1), Len1, PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void*)(Base + Offset1), NOP, Len1);//指令Nop掉防止写的时机不对发生变化
VirtualProtect((void*)(Base + Offset1), Len1, oldprot, &oldprot);
VirtualProtect((void*)(Base + Offset2), Len2, PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void*)(Base + Offset2), NOP, Len2);//指令Nop掉防止写的时机不对发生变化
VirtualProtect((void*)(Base + Offset2), Len2, oldprot, &oldprot);
VirtualProtect((void*)(Base + NameOffset), sizeof(NewName), PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void*)(Base + NameOffset), NewName, sizeof(NewName));//把名字写到内存中
VirtualProtect((void*)(Base + NameOffset), sizeof(NewName), oldprot, &oldprot);
VirtualProtect((void*)(Base + flagOffset), sizeof(flag), PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void*)(Base + flagOffset), flag, sizeof(flag));//把flag写到内存中
VirtualProtect((void*)(Base + flagOffset), sizeof(flag), oldprot, &oldprot);
printf("Change Name Success\n");
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
patch();
patchname();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
结果
看雪ID:xi@0ji233
https://bbs.kanxue.com/user-home-919002.htm
# 往期推荐
3、安卓加固脱壳分享
球分享
球点赞
球在看