逆向题,找到关键比较位了,但是还原后字符不对。
本帖最后由 wgf4242 于 2023-9-9 22:43 编辑https://wwi.lanzoup.com/i8QsB17ttr0j
有些花指令简单修复一下 就行了。
···
看起来关键点在这。我把 v27 全部输出和 v41 异或了一下但不对。 不知道哪里有问题。求助一下。
汇编中比较时
```
while ( i1 < 38 )
{
LOBYTE(v27) = j_encode();
v27 = (unsigned __int8)v27;
if ( ((unsigned __int8)v27 ^ Str) != (unsigned __int8)v41 )
{
sub_C513E3(v26);
LOBYTE(v42) = 6;
sub_C513E3(v25);
LOBYTE(v42) = 7;
```
汇编中比较字符时,一个字符中有符号扩展,一个是无符号扩展,一但超了0x80扩展后就变负数了无法通过。可能哪里有其他的代码控制吧。
```
.text:00596D64 mov , eax
.text:00596D6A ; 160: if ( ((unsigned __int8)v27 ^ Str) != (unsigned __int8)v41 )
.text:00596D6A mov eax,
.text:00596D70 movsx ecx,
.text:00596D78 xor ecx,
.text:00596D7E mov edx,
.text:00596D84 movzx eax,
.text:00596D89 cmp ecx, eax
```
输出出来字符不对啊。
```python
v27 =
enc = bytes.fromhex('C26CFCB3A78EF58381CBBFD5C2CE83BDE66AA5A844F5455950D80398F77487ACC53E382F0768')
for a, b in zip(v27, enc):
r = a ^ b
print(chr(r),end='')
# print(f"{r:02x}", end='')
``` 本帖最后由 爱飞的猫 于 2023-9-10 05:32 编辑
反调试没过的话会得到错误结果。
如果不过反调试,可以直接这样打补丁:
```x86asm
00416D5A | E8 29A7FFFF | call luoing.411488 | <-- get next rand
00416D5F | 25 FF000000 | and eax, 0xFF |
00416D64 | 8D95 7CFDFFFF | lea edx, dword ptr ss: |
00416D6A | 8B8D 78FDFFFF | mov ecx, dword ptr ss: |
00416D70 | 880411 | mov byte ptr ds:, al |
00416D73 | 41 | inc ecx |
00416D74 | 898D 78FDFFFF | mov dword ptr ss:, ecx |
00416D7A | 83F9 30 | cmp ecx, 0x30 | 多写一点无所谓
00416D7D | 7E DB | jle luoing.416D5A |
00416D7F | 90 | nop |
00416D80 | 90 | nop |
00416D81 | EB FC | jmp luoing.416D7F | 死循环
```
然后运行,输入假码 `01234567890123456789012345678901234567`,等几秒后附加调试器,然后在 `00416D7F` 中断等待断点触发。此时 dump 内存 `ebp-0x284` 附近得到真的密钥。
dump 出来后手动 xor 一下(其实也可以直接在上面的汇编做 xor):
```py
data_flag = b''.join([
b'\xC2\x6C\xFC\xB3\xA7\x8E\xF5\x83\x81\xCB\xBF\xD5\xC2\xCE\x83\xBD',
b'\xE6\x6A\xA5\xA8\x44\xF5\x45\x59\x50\xD8\x03\x98\xF7\x74\x87\xAC',
b'\xC5\x3E\x38\x2F\x07\x68'])
data_twist_rand = b''.join([
b'\x86\x2D\xAF\xF0\xF3\xC8\x8E\xF4\xE4\xA7\xDC\xBA\xAF\xAB\xDC\xCF',
b'\x83\x1C\xC0\xDA\x37\x90\x1A\x30\x24\x87\x6A\xEB\xA8\x07\xE8\xF3',
b'\xA6\x51\x57\x43\x26\x15\xA9\x21\x99\xCC\x45\x54\x4A\x06\x31\x78',
b'\xB5'])
result = bytearray(data_flag)
for i in range(len(result)):
result ^= data_twist_rand
# "DASCTF{welcome_reverse_it_is_so_cool!}"
print(result.decode('ascii'))
```
P.S. 我也没过他反调试,也不知道在哪检测的… 随手试了下改文件发现能得到正确结果就没管他了。
通过搜索常量,~~随机数生成器应该是 Mersenne Twister 魔改(?)~~ 最后发现是标准的【Mersenne Twister 19937】随机数生成器。
参考实现:https://github.com/woodruffw/snippets/blob/4fcc1e0/mersenne/mersenne.c
P.S.2 我搜了下这个 Flag 没发现其他人的 writeup,这是一个还在进行中的 CTF?如果是的话,作业请自己做 _(:3__
妙啊。。。打补丁这个方法真好。
一个省赛,结束好几天了,搜不到writeup的。。。
```
通过搜索常量,随机数生成器应该是 Mersenne Twister 魔改(?)
```
这是什么奇怪的知识的。
我去学一下。 本帖最后由 爱飞的猫 于 2023-9-10 06:02 编辑
wgf4242 发表于 2023-9-10 05:28
妙啊。。。打补丁这个方法真好。
一个省赛,结束好几天了,搜不到writeup的。。。
把逆出来的和 IDA 看到的代码综合了下:
```c
#include <stdint.h>
#include <stdio.h>
// Mersenne Twister 19937
// 参考维基百科说明
// https://en.wikipedia.org/wiki/Mersenne_Twister
struct MT19937Ctx {
uint32_t index;
uint32_t state;
};
void mt19937_init(struct MT19937Ctx *ctx, int seed) {
ctx->index = 624;
uint32_t value = seed;
ctx->state = seed;
for (int i = 1; i < 624; ++i) {
value = 0x6C078965 * (value ^ (value >> 30)) + i;
ctx->state = value;
}
}
void mt19937_twist(struct MT19937Ctx *ctx) {
for (uint32_t i = 0; i < 624; ++i) {
uint32_t y =
(ctx->state & 0x80000000) | (ctx->state[(i + 1) % 624] & 0x7FFFFFFF);
uint32_t xor_value = (y & 1) * 0x9908B0DF;
ctx->state = ctx->state[(i + 397) % 624] ^ (y >> 1) ^ xor_value;
}
}
uint32_t mt19937_next(struct MT19937Ctx *ctx) {
if (ctx->index >= 624) {
mt19937_twist(ctx);
ctx->index = 0;
}
uint32_t result = ctx->state;
result ^= result >> 0x0B;
result ^= (result << 0x07) & 0x9D2C5680;
result ^= (result << 0x0F) & 0xEFC60000;
result ^= result >> 0x12;
return result;
}
int main() {
struct MT19937Ctx mt19937 = {};
mt19937_init(&mt19937, 0x44C);
uint8_t ctf_flag = {0xC2, 0x6C, 0xFC, 0xB3, 0xA7, 0x8E, 0xF5, 0x83,
0x81, 0xCB, 0xBF, 0xD5, 0xC2, 0xCE, 0x83, 0xBD,
0xE6, 0x6A, 0xA5, 0xA8, 0x44, 0xF5, 0x45, 0x59,
0x50, 0xD8, 0x03, 0x98, 0xF7, 0x74, 0x87, 0xAC,
0xC5, 0x3E, 0x38, 0x2F, 0x07, 0x68};
for (int i = 0; i < sizeof(ctf_flag); i++) {
ctf_flag ^= (uint8_t)(mt19937_next(&mt19937));
}
printf("flag: %.38s\n", (char *)&ctf_flag);
}
```
如果利用 cpp 标准库:
```cpp
#include <array>
#include <cstdint>
#include <iostream>
#include <random>
// 调试器检测
constexpr bool kDebuggerFound = true;
int main() {
std::mt19937 mt19937(kDebuggerFound ? 0x7D1 : 0x44C);
std::array<uint8_t, 38> ctf_flag = {
0xC2, 0x6C, 0xFC, 0xB3, 0xA7, 0x8E, 0xF5, 0x83, 0x81, 0xCB,
0xBF, 0xD5, 0xC2, 0xCE, 0x83, 0xBD, 0xE6, 0x6A, 0xA5, 0xA8,
0x44, 0xF5, 0x45, 0x59, 0x50, 0xD8, 0x03, 0x98, 0xF7, 0x74,
0x87, 0xAC, 0xC5, 0x3E, 0x38, 0x2F, 0x07, 0x68};
for (auto &v : ctf_flag) {
v ^= mt19937();
}
std::cout << "flag: ";
for (auto &v : ctf_flag) {
std::cout << (char)(v);
}
std::cout << std::endl;
}
```
---
反调试的话,其实只要装了任何一个过反调试的插件就能过了。
```c
BOOL __stdcall TlsCallback_0_0(int a1, int a2, int a3)
{
HANDLE CurrentProcess; // eax
BOOL result; // eax
BOOL pbDebuggerPresent; // BYREF
pbDebuggerPresent = 0;
CurrentProcess = GetCurrentProcess();
result = CheckRemoteDebuggerPresent(CurrentProcess, &pbDebuggerPresent);
if ( pbDebuggerPresent )
g_seed = 0x7D1;
return result;
}
```
本帖最后由 ri5e 于 2023-10-13 11:41 编辑
过这种反调试,ida有什么反调试的插件吗
页:
[1]