Hgame-final复盘

news/2025/3/17 11:13:36/文章来源:https://www.cnblogs.com/T0fV404/p/18776416

RE

Crackme

获得name为"hgame"的许可证

__int64 __fastcall sub_1400123F0(HINSTANCE a1)
{char *v1; // rdi__int64 i; // rcxchar v4[32]; // [rsp+0h] [rbp-60h] BYREFchar v5; // [rsp+60h] [rbp+0h] BYREFWNDCLASSW WndClass; // [rsp+70h] [rbp+10h] BYREFHWND hWnd; // [rsp+D8h] [rbp+78h]struct tagMSG Msg; // [rsp+F8h] [rbp+98h] BYREFv1 = &v5;for ( i = 58i64; i; --i ){*(_DWORD *)v1 = -858993460;v1 += 4;}sub_1400113D9(&unk_1400240AD);WndClass.lpfnWndProc = (WNDPROC)sub_140011230;WndClass.hInstance = a1;WndClass.lpszClassName = L"Crackme";WndClass.hbrBackground = (HBRUSH)GetStockObject(0);WndClass.hCursor = LoadCursorW(0i64, (LPCWSTR)0x7F00);WndClass.hIcon = LoadIconW(0i64, (LPCWSTR)0x7F00);WndClass.lpszMenuName = 0i64;WndClass.style = 3;WndClass.cbClsExtra = 0;WndClass.cbWndExtra = 0;RegisterClassW(&WndClass);hWnd = CreateWindowExW(0, L"Crackme", L"Crackme", 0xCC0000u, 0, 0, 800, 600, 0i64, 0i64, a1, 0i64);ShowWindow(hWnd, 1);UpdateWindow(hWnd);while ( GetMessageW(&Msg, 0i64, 0, 0) ){TranslateMessage(&Msg);DispatchMessageW(&Msg);}return sub_140011366(v4, &unk_14001AD80);
}

注册窗口,不管这些,直接看主函数sub_140011230逻辑:

LRESULT __fastcall sub_140011B10(HWND a1, UINT a2, WPARAM a3, LPARAM a4)
{char *v4; // rdi__int64 i; // rcxDWORD v6; // eaxDWORD v7; // eaxLRESULT v8; // raxLRESULT v9; // rdichar v11[32]; // [rsp+0h] [rbp-60h] BYREFchar v12; // [rsp+60h] [rbp+0h] BYREFstruct tagRECT Rect; // [rsp+68h] [rbp+8h] BYREFint nWidth; // [rsp+94h] [rbp+34h]int nHeight; // [rsp+B4h] [rbp+54h]int v16; // [rsp+D4h] [rbp+74h]int v17; // [rsp+F4h] [rbp+94h]PVOID Block; // [rsp+118h] [rbp+B8h]PVOID pvData; // [rsp+138h] [rbp+D8h]LPARAM v20; // [rsp+158h] [rbp+F8h]int v21; // [rsp+174h] [rbp+114h]int v22; // [rsp+194h] [rbp+134h]int X; // [rsp+1B4h] [rbp+154h]int Y; // [rsp+1D4h] [rbp+174h]int v25; // [rsp+1F4h] [rbp+194h]int v26; // [rsp+214h] [rbp+1B4h]int v27; // [rsp+234h] [rbp+1D4h]LSTATUS ValueA; // [rsp+254h] [rbp+1F4h]DWORD pdwType[8]; // [rsp+274h] [rbp+214h] BYREFDWORD pcbData[8]; // [rsp+294h] [rbp+234h] BYREF__int16 v31; // [rsp+2B4h] [rbp+254h]__int16 v32; // [rsp+2D4h] [rbp+274h]LPARAM v33; // [rsp+2F8h] [rbp+298h]CHAR Str[56]; // [rsp+318h] [rbp+2B8h] BYREFCHAR String[516]; // [rsp+350h] [rbp+2F0h] BYREFUINT v36; // [rsp+554h] [rbp+4F4h]v4 = &v12;for ( i = 226i64; i; --i ){*(_DWORD *)v4 = -858993460;v4 += 4;}sub_1400113D9(&unk_1400240AD);nWidth = 100;nHeight = 30;v16 = 550;v17 = 30;Block = 0i64;pvData = 0i64;v36 = a2;if ( a2 == 1 ){v20 = a4;GetClientRect(a1, &Rect);v21 = Rect.right - Rect.left;v22 = Rect.bottom - Rect.top;X = (Rect.right - Rect.left - nWidth) / 2;Y = 2 * ((Rect.bottom - Rect.top - nHeight) / 3);v25 = (Rect.right - Rect.left - v16) / 2;v26 = Y - 50;v27 = Y - 100;pcbData[0] = 0;ValueA = RegGetValueA(HKEY_CURRENT_USER, SubKey, "Name", 1u, pdwType, 0i64, pcbData);if ( !ValueA ){Block = malloc(pcbData[0]);j_memset(Block, 0, pcbData[0]);ValueA = RegGetValueA(HKEY_CURRENT_USER, SubKey, "Name", 1u, pdwType, Block, pcbData);}ValueA = RegGetValueA(HKEY_CURRENT_USER, SubKey, "License", 1u, pdwType, 0i64, pcbData);if ( !ValueA ){pvData = malloc(pcbData[0]);j_memset(pvData, 0, pcbData[0]);ValueA = RegGetValueA(HKEY_CURRENT_USER, SubKey, "License", 1u, pdwType, pvData, pcbData);}if ( !Block || !pvData ){Block = malloc(5ui64);j_memset(Block, 0, 5ui64);pvData = malloc(8ui64);j_memset(pvData, 0, 8ui64);strncpy((char *)Block, "Name", 4ui64);strncpy((char *)pvData, "License", 7ui64);}qword_14001E208 = (__int64)CreateWindowExW(0,L"button",L"Cilck",0x50000000u,X,Y,nWidth,nHeight,a1,(HMENU)0x3E8,*(HINSTANCE *)(v20 + 8),0i64);hWnd = CreateWindowExA(0,"edit",(LPCSTR)pvData,0x50800000u,v25,v26,v16,v17,a1,(HMENU)0x3E9,*(HINSTANCE *)(v20 + 8),0i64);qword_14001E218 = CreateWindowExA(0,"edit",(LPCSTR)Block,0x50800000u,v25,v27,v16,v17,a1,(HMENU)0x3EA,*(HINSTANCE *)(v20 + 8),0i64);goto LABEL_24;}if ( v36 == 2 ){free(Block);free(pvData);PostQuitMessage(0);
LABEL_24:v8 = 0i64;goto LABEL_25;}if ( v36 == 273 ){v32 = WORD1(a3);v31 = a3;v33 = a4;if ( (unsigned __int16)a3 == 1000 && !v32 && hWnd && qword_14001E218 ){GetWindowTextA(hWnd, String, 70);GetWindowTextA(qword_14001E218, Str, 8);if ( (unsigned int)qword_14001E1F0(Str, String) ){v6 = j_strlen(Str);RegSetKeyValueA(HKEY_CURRENT_USER, SubKey, "Name", 1u, Str, v6);v7 = j_strlen(String);RegSetKeyValueA(HKEY_CURRENT_USER, SubKey, "License", 1u, String, v7);MessageBoxA(a1, "Success!", "Crackme", 0);}else{MessageBoxA(a1, "Failed!", "Crackme", 0);}}goto LABEL_24;}v8 = DefWindowProcW(a1, a2, a3, a4);
LABEL_25:v9 = v8;sub_140011366(v11, &unk_14001AF20);return v9;
}

主要部分是:

if ( (unsigned __int16)a3 == 1000 && !v32 && hWnd && qword_14001E218 ){GetWindowTextA(hWnd, String, 70);GetWindowTextA(qword_14001E218, Str, 8);if ( (unsigned int)qword_14001E1F0(Str, String) ){v6 = j_strlen(Str);RegSetKeyValueA(HKEY_CURRENT_USER, SubKey, "Name", 1u, Str, v6);v7 = j_strlen(String);RegSetKeyValueA(HKEY_CURRENT_USER, SubKey, "License", 1u, String, v7);MessageBoxA(a1, "Success!", "Crackme", 0);}else{MessageBoxA(a1, "Failed!", "Crackme", 0);}}

这里读取了传入文本进行校验,我们交叉应用看一下qword_14001E1F0(Str, String)

发现有个加载库函数:

HMODULE sub_1400118A0()
{HMODULE result; // raxsub_1400113D9(&unk_1400240AD);result = LoadLibraryA(LibFileName);hModule = result;if ( result ){result = (HMODULE)GetProcAddress(hModule, "Check");qword_14001E1F0 = (__int64 (__fastcall *)(_QWORD, _QWORD))result;}return result;
}

去看看提供的nobody.dll文件查看Check函数:

_BOOL8 __fastcall Check(char *name, char *license)
{__int64 hash; // [rsp+48h] [rbp+28h]char *true_license; // [rsp+68h] [rbp+48h]sub_180011357(&unk_1800240A3);j_strlen(name);hash = SHA256(name);xtea(hash);true_license = (char *)format(hash);return strncmp(true_license, license, 0x40ui64) == 0;
}

动调发现调不了,qword_14001E1F0的值为0,不是很理解,因为这里是错的,我都没看出为什么,但是z佬说这是符号修饰.无语了,看了下汇编,ida又优化了,讨厌ida.

导出表有个tls回调看一下,发现调用RemoveVectoredExceptionHandlerapi,说明有注册veh异常调用.

veh是进程的异常调用,seh是线程的异常调用,捕获异常的优先级为:调试器->VEH->SEH(这里导致我不知道为什么跳转不了)

导入表用注册,交叉应用看一下.

PVOID sub_140011920()
{PVOID result; // raxsub_1400113D9(&unk_1400240AD);result = AddVectoredExceptionHandler(1u, Handler);Handle = result;return result;
}

handler:

__int64 __fastcall Handler_0(__int64 a1)
{char *v1; // rdi__int64 i; // rcxchar v4[32]; // [rsp+0h] [rbp-20h] BYREFchar v5[304]; // [rsp+20h] [rbp+0h] BYREFv1 = v5;for ( i = 26i64; i; --i ){*(_DWORD *)v1 = -858993460;v1 += 4;}sub_1400113D9(&unk_1400240AD);memset(&v5[16], 0, 0x40ui64);if ( **(_DWORD **)a1 == -1073741819 ){if ( *(_QWORD *)(*(_QWORD *)(a1 + 8) + 248i64) || (*(_DWORD *)(*(_QWORD *)(a1 + 8) + 68i64) & 0x100) != 0 ){RemoveVectoredExceptionHandler(Handle);MessageBoxA(0i64, "Error", "Crackme", 0);exit(0);}*(_QWORD *)(*(_QWORD *)(a1 + 8) + 248i64) = hModule + 18100;}sub_140011366(v4, &unk_14001AFD0);return 0xFFFFFFFFi64;
}

这里是捕获内存异常访问的报错,读取了上下文,查看有无被硬件断点和单步调试.

没有就把rip修改

值得注意一点:这里18100是int型加上18100,什么意思呢?

int a[10] = {0};
int *pointer = a;
pointer++;

对于int指针的pointer这里是加1,但是对于内存它加了32位.

所以我们要去看汇编,得到11AD0h,这才是内存里的偏移值.

我们动调,输入hgame

image-20250317102152084

内存异常访问

image-20250317102341490

点击yes.

调到相应内存位置,c一下,p一下:

__int64 __fastcall sub_7FFF3D881AD0(__int64 a1, __int64 a2)
{char *v2; // rdi__int64 i; // rcx__int64 v4; // rcx__int64 v5; // rax__int64 v6; // rdichar v8[32]; // [rsp+0h] [rbp-20h] BYREFchar v9[4]; // [rsp+20h] [rbp+0h] BYREFint v10; // [rsp+24h] [rbp+4h]__int64 v11; // [rsp+48h] [rbp+28h]int v12[12]; // [rsp+68h] [rbp+48h] BYREF__int64 v13; // [rsp+98h] [rbp+78h]int j; // [rsp+B4h] [rbp+94h]unsigned __int64 v15; // [rsp+188h] [rbp+168h]v2 = v9;for ( i = 46i64; i; --i ){*(_DWORD *)v2 = -858993460;v2 += 4;}v15 = (unsigned __int64)v9 ^ qword_7FFF3D88F000;((void (__fastcall *)(void *))unk_7FFF3D881357)(&unk_7FFF3D8940A3);v10 = ((__int64 (__fastcall *)(__int64))unk_7FFF3D881186)(a1);qmemcpy(v12, "Seven123456Seven", 16);v11 = ((__int64 (__fastcall *)(__int64))unk_7FFF3D881159)(a1);LOBYTE(v4) = 32;((void (__fastcall *)(__int64, int *, __int64, __int64))unk_7FFF3D881078)(v4, v12, v11, v11);v13 = ((__int64 (__fastcall *)(__int64))unk_7FFF3D881104)(v11);for ( j = 0; j < 64; ++j ){if ( *(char *)(v13 + j) != *(char *)(a2 + j) ){v5 = 0i64;goto LABEL_10;}}v5 = 1i64;
LABEL_10:v6 = v5;((void (__fastcall *)(char *, void *))unk_7FFF3D8812F3)(v8, &unk_7FFF3D88B950);return v6;
}

直接上官方wp:

第一次加密,分析一下知道这是SHA256

第二次是key 为Seven123456Seven的SM4 ECB加密

没换表 常量直接搜

可以直接动调dump出来.

battler

不多写,其实确实简单,但是我当时又困又急,脚本写错没时间改了.

其实程序的逻辑还是清楚的,哪怕用一堆abcd来代替,哪怕activity不写清楚.

直接搜索score,能发现一个f9635g,猜测是score:

public void e() {M.a(0.15f, 0.15f, 0.2f, 1.0f);if (!this.f9644p) {this.f9629a.k();this.f9629a.y(this.f9632d, this.f9633e - 400.0f, this.f9634f - 100.0f);this.f9640l.b(this.f9629a);this.f9641m.b(this.f9629a);i();this.f9630b.draw(this.f9629a, "Score: " + this.f9635g, 100.0f, this.f9634f - 50.0f);this.f9630b.draw(this.f9629a, "Health: " + this.f9636h.f9669y, 100.0f, this.f9634f - 150.0f);this.f9629a.e();}

交叉应用继续跟:

public void a(final d dVar) {int i2;dVar.f9644p = true;AndroidLauncher androidLauncher = this.f9724a;GameService gameService = androidLauncher.f7731w;gameService.f7735b = dVar.f9635g;androidLauncher.startService(androidLauncher.f7730v);do {i2 = gameService.f7736c;} while (i2 == 0);String str = "游戏结束\n";if (i2 == 1) {str = "游戏结束\n菜就多练!!!";} else if (i2 == 2) {str = "游戏结束\n恭喜你,通过了考验!!My Battler";} else if (i2 == 3) {str = "游戏结束\n我早就发现你了,作弊者";}
package com.nobody.battle.android;import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;/* loaded from: classes.dex */
public class GameService extends Service {/* renamed from: a, reason: collision with root package name */private final IBinder f7734a = new a();/* renamed from: b, reason: collision with root package name */public int f7735b = 0;/* renamed from: c, reason: collision with root package name */public int f7736c = 0;public class a extends Binder {public a() {}GameService a() {return GameService.this;}}static {System.loadLibrary("GameService");}static native int aaaa(int i2);@Override // android.app.Servicepublic IBinder onBind(Intent intent) {return this.f7734a;}@Override // android.app.Servicepublic void onDestroy() {super.onDestroy();}@Override // android.app.Servicepublic int onStartCommand(Intent intent, int i2, int i3) {this.f7736c = aaaa(this.f7735b);return super.onStartCommand(intent, i2, i3);}
}

有个本地函数aaaa,去so看看,是个被ollvm混淆的xxtea,看的很烦,然后脚本写错了,又不想改,也没时间了,就没做了.

其实可以用frida,但是我frida学的不多,hook不来,而且我看后续log_print也要hook(不知道,官方wp说的)

先粘贴一下官方hook脚本:

function hookTest() {let GameService = Java.use("com.nobody.battle.android.GameService");GameService["aaaa"].implementation = function (i2) {console.log(`GameService.aaaa is called: i2=${i2}`);let result = this["aaaa"](1000000);console.log(`GameService.aaaa result=${result}`);return result;};var liblog = Module.findBaseAddress("liblog.so");if (liblog) {// 查找 __android_log_print 函数的地址var logPrint = Module.findExportByName("liblog.so", "__android_log_print");if (logPrint) {// 对 __android_log_print 函数进行 HookInterceptor.attach(logPrint, {// 在函数调用前执行的逻辑onEnter: function (args) {// args[0] 是日志级别,args[1] 是日志标签,args[2] 是日志格式字符串var priority = args[0].toInt32();var tag = Memory.readUtf8String(args[1]);var format = Memory.readUtf8String(args[2]);var message = Memory.readUtf8String(args[3]);// 在 Hook 之前输出函数调用前的日志信息if (tag == "Native") {console.log(`__android_log_print(${priority}, "${tag}", "${format}", "${message}")`);}},// 在函数调用后执行的逻辑onLeave: function (retval) {console.log("After __android_log_print, return value: " + retval.toInt32());},});} else {console.log("__android_log_print not found in liblog.so");}} else {console.log("liblog.so not found");}
}
function main() {Java.perform(function () {hookTest();});
}
setImmediate(main);

babyre

用那些沟槽的128位符号写的模拟rc4,ai一把梭.

不过我自己看不出来()

misc

vidar知识大问答

还好

罗师傅的图片(忘了题目名字)

百度识图可得图片地方在客运中心站pictrue

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/900295.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

011 App宽高铺满和Element-Plus的CS

1、让app的盒子沾满屏幕 首先我们给app一个底色 可以看到并没有占满 可以看到app在这个盒子里面 所以应该先让这个盒子占满 方法一:(应为需要改index.html,不推荐,但是可以看一下) 可以看到 方法二(推荐) 这段代码,用来设置元素的尺寸:width: 100vw;:width表示元素…

5. 创建一个栅栏布局组件-DeepSeek辅助编程

在deepseek中输入:创建一个vue组件 组件实现栅栏布局的功能 deepseek返回的代码: Row.vue<template><div class="grid-row":style="rowStyle":class="rowClass"><slot></slot></div> </template><scri…

突破卡脖子工程:6大信创项目管理平台横向测评

随着信息技术的快速发展,信创项目管理平台在推动我国信息技术创新和产业发展方面发挥着重要作用。为了帮助读者更好地了解和选择适合的信创项目管理平台,本文对 6 大信创项目管理平台进行了横向测评。 禅道——信创国产化项目管理解决方案 禅道是一款国产的项目管理软件,禅道…

夜莺监控如何对接飞书、飞书卡片发送告警

新版通知规则的介绍文章:夜莺监控巨大革新:抽象出通知规则,增强告警通知的灵活性 新版通知规则对接钉钉:夜莺监控 v8.0 新版通知规则 | 对接钉钉告警 新版通知规则对接企微:夜莺监控 v8.0 新版通知规则 | 对接企微告警本文对背景信息不做额外描述了,大家一定要先看看上面…

网络攻防实验三

1.实验内容 (1)动手实践tcpdump 使用tcpdump开源软件对在本机上访问www.tianya.cn网站过程进行嗅探,回答问题:你在访问www.tianya.cn网站首页时,浏览器将访问多少个Web服务器?他们的IP地址都是什么? (2)动手实践Wireshark 使用Wireshark开源软件对在本机上以TELNET方式…

Debian:apt-get命令汇总

apt-get命令 是Debian Linux发行版中的APT软件包管理工具。所有基于Debian的发行(常见的 10 个基于 Debian 的 Linux 发行版)都使用这个包管理系统。deb包可以把一个应用的文件包在一起,大体就如同Windows上的安装文件。语法 apt-get [OPTION] PACKAGE 选项 apt-get install…

Edge浏览器的设备仿真模式下显示鼠标指针

在使用Edge浏览器进行网页开发时,设备仿真模式是一个非常有用的工具,它可以帮助开发者模拟不同设备上的用户体验。但在设备仿真模式下,鼠标指针会显示为一个圆形触摸指示器,而不是我们熟悉的鼠标箭头,这可能会对精确测试鼠标交互造成影响。 改变方法 在设备仿真工具栏中,…

openmanus 代码分析 #2 - agent classes

根据你提供的 agent 目录下各个类的信息,下面是对应的 PlantUML 代码,用于绘制类图展示这些类之间的关系:@startuml定义抽象基类 abstract class BaseAgent {+ name: str+ description: Optional[str]+ system_prompt: Optional[str]+ next_step_prompt: Optional[str]+ l…

实践四:数据模型与数据库

实践四:数据模型与数据库 内容概述:本节课我们将引入数据模型(model),通过创建数据模型和数据表,我们就可以将信息存储在数据库中,并将数据库中的信息呈现在页面上。 1. 在完成实践一、实践二、实践三的基础上开始本项目,进入激活虚拟环境。pipenv shel提示:接下来我们…

clickhouse 开启认证 SQL 方式

ClickHouse 访问控制 RBAC 用户账户:包含身份信息、权限、允许的主机、角色和设置。 角色:权限容器,可分配给用户或其他角色。 行策略:定义表中行的可见性。 设置配置文件:集中管理用户/角色的配置参数。 配额:限制资源使用(如查询次数、内存)。 权限层级 权限按层级划…

No.66 Vue---Vue引入路由配置、路由传递参数、嵌套路由配置

一、Vue引入路由配置在Vue中,我们可以通过 vue-router 路由管理页面之间的关系 Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举.1.1 在vue中引入路由 第一步:安装路由npm install -save vue-router第二步:配置独立的路由…

开源!Django-Vue3-Admin的Python后台管理系统

DjangoAdmin 是一个基于 Django + Vue3 的前后端分离的后台管理系统,采用了最新的前后端技术栈,内置了丰富的功能模块,可以帮助开发者快速搭建企业级中后台产品。Django-Vue3-Admin 项目简介 Django-Vue3-Admin 是一个基于 Django + Vue3 的前后端分离的后台管理系统,采用了…