wgf4242 发表于 2023-9-9 22:19

逆向题,找到关键比较位了,但是还原后字符不对。

本帖最后由 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 00:01

本帖最后由 爱飞的猫 于 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__

wgf4242 发表于 2023-9-10 05:28

妙啊。。。打补丁这个方法真好。

一个省赛,结束好几天了,搜不到writeup的。。。
```

通过搜索常量,随机数生成器应该是 Mersenne Twister 魔改(?)
```
这是什么奇怪的知识的。
我去学一下。

爱飞的猫 发表于 2023-9-10 05:34

本帖最后由 爱飞的猫 于 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:40

本帖最后由 ri5e 于 2023-10-13 11:41 编辑

过这种反调试,ida有什么反调试的插件吗
页: [1]
查看完整版本: 逆向题,找到关键比较位了,但是还原后字符不对。