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;
}
动调发现调不了,无语了,看了下汇编,ida又优化了,讨厌ida.qword_14001E1F0
的值为0,不是很理解,因为这里是错的,我都没看出为什么,但是z佬说这是符号修饰.
导出表有个tls回调看一下,发现调用RemoveVectoredExceptionHandler
api,说明有注册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
内存异常访问
点击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知识大问答
还好
罗师傅的图片(忘了题目名字)
百度识图可得图片地方在客运中心站