逆向攻防世界CTF系列41-EASYHOOK
看题目是一个Hook类型的,第一次接触,虽然学过相关理论,可以看我的文章
Hook入门(逆向)-CSDN博客
题解参考:https://www.cnblogs.com/c10udlnk/p/14214057.html和[攻防世界逆向高手题之EASYHOOK-CSDN博客](https://blog.csdn.net/xiao__1bai/article/details/119920369)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| int __cdecl main(int argc, const char **argv, const char **envp){ HANDLE FileA; DWORD NumberOfBytesWritten; char Buffer[32];
sub_401370(aPleaseInputFla); scanf("%31s", Buffer); if ( strlen(Buffer) == 19 ){ sub_401220(); FileA = CreateFileA(FileName, 0x40000000u, 0, 0, 2u, 0x80u, 0); WriteFile(FileA, Buffer, 0x13u, &NumberOfBytesWritten, 0); sub_401240(Buffer, &NumberOfBytesWritten); if ( NumberOfBytesWritten == 1 ) sub_401370(aRightFlagIsYou); else sub_401370(aWrong); system(Command); return 0; } else{ sub_401370(aWrong); system(Command); return 0; } }
|
跟进401240
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| int __cdecl sub_401240(const char *a1, _DWORD *a2) { int result; unsigned int v3; char v4[24];
result = 0; strcpy(v4, "This_is_not_the_flag"); v3 = strlen(a1) + 1; if ( (int)(v3 - 1) > 0 ) { while ( v4[a1 - v4 + result] == v4[result] ) { if ( ++result >= (int)(v3 - 1) ) { if ( result == 21 ) { result = (int)a2; *a2 = 1; } return result; } } } return result; }
|
v4[a1 - v4 + result] == v4[result]??,完全不通啊
还看了汇编源码,没看懂 0.0
看下sub_401220先
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| int sub_401220() { HMODULE LibraryA; DWORD CurrentProcessId; CurrentProcessId = GetCurrentProcessId(); hProcess = OpenProcess(0x1F0FFFu, 0, CurrentProcessId); LibraryA = LoadLibraryA(LibFileName); WriteFile_0 = (BOOL (__stdcall *)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED))GetProcAddress(LibraryA, ProcName); lpAddress = WriteFile_0; if ( !WriteFile_0 ) return sub_401370((int)aApi); unk_40C9B4 = *(_DWORD *)lpAddress; *((_BYTE *)&unk_40C9B4 + 4) = *((_BYTE *)lpAddress + 4); byte_40C9BC = -23; dword_40C9BD = (char *)sub_401080 - (char *)lpAddress - 5; return sub_4010D0(); }
|
这里犯了个错,不是-23而是0XE9,是JMP的机器码指令

byte_40C9BC和dword_40C9BD是相邻的,连起来就是 jmp xxxx四个字节
偏移地址=目标地址-当前地址-5(jmp和其后四位地址共占5个字节)。所以前面直接用E9,这里直接用偏移地址就省去编译生成机器码那一步。
看看sub_4010D0()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| BOOL sub_4010D0() { DWORD v1; DWORD flOldProtect;
v1 = 0; VirtualProtectEx(hProcess, lpAddress, 5u, 4u, &flOldProtect); WriteProcessMemory(hProcess, lpAddress, &byte_40C9BC, 5u, 0); return VirtualProtectEx(hProcess, lpAddress, 5u, flOldProtect, &v1); }
|
jmp那里会跳转到目标地址sub_401080处,双击跟踪该函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int __stdcall sub_401080( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { int v5;
v5 = sub_401000(lpBuffer, nNumberOfBytesToWrite); sub_401140(); WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); if ( v5 ) *lpNumberOfBytesWritten = 1; return 0; }
|
sub_401000();才是真正的加密函数
1 2 3 4 5 6 7 8 9 10
| BOOL sub_401140() { DWORD v1; DWORD flOldProtect;
v1 = 0; VirtualProtectEx(hProcess, lpAddress, 5u, 4u, &flOldProtect); WriteProcessMemory(hProcess, lpAddress, &unk_40C9B4, 5u, 0); return VirtualProtectEx(hProcess, lpAddress, 5u, flOldProtect, &v1); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| int __cdecl sub_401000(int a1, int a2) { char i; char v3; char v4; int v5;
for ( i = 0; i < a2; ++i ){ if ( i == 18 ){ *(_BYTE *)(a1 + 18) ^= 0x13u; } else{ if ( i % 2 ) v3 = *(_BYTE *)(i + a1) - i; else v3 = *(_BYTE *)(i + a1 + 2); *(_BYTE *)(i + a1) = i ^ v3; } } v4 = 0; if ( a2 <= 0 ) return 1; v5 = 0; while ( byte_40A030[v5] == *(_BYTE *)(v5 + a1) ){ v5 = ++v4; if ( v4 >= a2 ) return 1; } return 0; }
|
解密代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| enc = [ 0x61, 0x6A, 0x79, 0x67, 0x6B, 0x46, 0x6D, 0x2E, 0x7F, 0x5F, 0x7E, 0x2D, 0x53, 0x56, 0x7B, 0x38, 0x6D, 0x4C, 0x6E ]
flag=list("-------------------")
for i in range(len(enc)): if i == 18: enc[i] ^= 0x13 else: v3 = enc[i] ^ i if i % 2 == 1: flag[i] = chr(v3 + i) else: flag[i + 2] = chr(v3)
for i in range(len(enc)): print(flag[i],end='')
|
引用别人博客的一句话:
现在程序流程就很明朗了,粗略来看程序流程是CreateFileA->(lpAddress里存的指令)WriteFile->sub_401240,但是在经过sub_401220()的处理以后,变成了CreateFileA->(lpAddress里存的指令)sub_401080->sub_401240。
sub_401240中即使不符合也不会给NumberOfBytesWritten置成0