吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 793|回复: 4
收起左侧

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

[复制链接]
wgf4242 发表于 2023-9-9 22:19
本帖最后由 wgf4242 于 2023-9-9 22:43 编辑

https://wwi.lanzoup.com/i8QsB17ttr0j

有些花指令简单修复一下 就行了。

···

看起来关键点在这。我把 v27 全部输出和 v41[i1] 异或了一下但不对。 不知道哪里有问题。求助一下。

汇编中比较时

  while ( i1 < 38 )
  {
    LOBYTE(v27) = j_encode();
    v27 = (unsigned __int8)v27;
    if ( ((unsigned __int8)v27 ^ Str[i1]) != (unsigned __int8)v41[i1] )
    {
      sub_C513E3(v26);
      LOBYTE(v42) = 6;
      sub_C513E3(v25);
      LOBYTE(v42) = 7;

汇编中比较字符时,一个字符中有符号扩展,一个是无符号扩展,一但超了0x80扩展后就变负数了无法通过。可能哪里有其他的代码控制吧。

.text:00596D64 mov     [ebp+var_294], eax
.text:00596D6A ; 160:     if ( ((unsigned __int8)v27 ^ Str[i1]) != (unsigned __int8)v41[i1] )
.text:00596D6A mov     eax, [ebp+i1]
.text:00596D70 movsx   ecx, [ebp+eax+Str]
.text:00596D78 xor     ecx, [ebp+var_294]
.text:00596D7E mov     edx, [ebp+i1]
.text:00596D84 movzx   eax, [ebp+edx+var_3C]
.text:00596D89 cmp     ecx, eax

输出出来字符不对啊。

v27 = [0x0, 0x4, 0x86, 0x10, 0xba, 0xe6, 0x65, 0xd0, 0x1, 0x80, 0x2a, 0x44, 0xab, 0x3c, 0x2c, 0xd7, 0x1a, 0x79, 0x4, 0x27, 0x93, 0xfa, 0x48, 0x69, 0xe1, 0x56, 0x8d, 0xaf, 0x97, 0x81, 0x76, 0xc5, 0x70, 0xb9, 0xc6, 0x3e, 0x92, 0x65]
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 编辑

反调试没过的话会得到错误结果。

如果不过反调试,可以直接这样打补丁:

00416D5A | E8 29A7FFFF              | call luoing.411488                      | <-- get next rand
00416D5F | 25 FF000000              | and eax, 0xFF                           |
00416D64 | 8D95 7CFDFFFF            | lea edx, dword ptr ss:[ebp-0x284]       |
00416D6A | 8B8D 78FDFFFF            | mov ecx, dword ptr ss:[ebp-0x288]       |
00416D70 | 880411                   | mov byte ptr ds:[ecx+edx], al           | 
00416D73 | 41                       | inc ecx                                 |
00416D74 | 898D 78FDFFFF            | mov dword ptr ss:[ebp-0x288], 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):

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[i] ^= data_twist_rand[i]

# "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__

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
wgf4242 + 1 + 1 热心回复!

查看全部评分

 楼主| wgf4242 发表于 2023-9-10 05:28
妙啊。。。打补丁这个方法真好。

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

通过搜索常量,随机数生成器应该是 Mersenne Twister 魔改(?)

这是什么奇怪的知识的。
我去学一下。

点评

把逆出来的和 IDA 看到的代码综合了下: [md]```c #include #include // Mersenne Twister 19937 // 参考维基百科说明 // https://en.wikipedia.org/wiki/Mersenne_Twister // C++ 标准库有自带的实  详情 回复 发表于 2023-9-10 05:34
爱飞的猫 发表于 2023-9-10 05:34
本帖最后由 爱飞的猫 于 2023-9-10 06:02 编辑
wgf4242 发表于 2023-9-10 05:28
妙啊。。。打补丁这个方法真好。

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

把逆出来的和 IDA 看到的代码综合了下:

#include <stdint.h>
#include <stdio.h>

// Mersenne Twister 19937
// 参考维基百科说明
//   https://en.wikipedia.org/wiki/Mersenne_Twister
struct MT19937Ctx {
  uint32_t index;
  uint32_t state[624];
};

void mt19937_init(struct MT19937Ctx *ctx, int seed) {
  ctx->index = 624;

  uint32_t value = seed;
  ctx->state[0] = seed;
  for (int i = 1; i < 624; ++i) {
    value = 0x6C078965 * (value ^ (value >> 30)) + i;
    ctx->state[i] = value;
  }
}

void mt19937_twist(struct MT19937Ctx *ctx) {
  for (uint32_t i = 0; i < 624; ++i) {
    uint32_t y =
        (ctx->state[i] & 0x80000000) | (ctx->state[(i + 1) % 624] & 0x7FFFFFFF);
    uint32_t xor_value = (y & 1) * 0x9908B0DF;
    ctx->state[i] = 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[ctx->index++];

  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[38] = {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[i] ^= (uint8_t)(mt19937_next(&mt19937));
  }
  printf("flag: %.38s\n", (char *)&ctf_flag[0]);
}

如果利用 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;
}

反调试的话,其实只要装了任何一个过反调试的插件就能过了。

BOOL __stdcall TlsCallback_0_0(int a1, int a2, int a3)
{
  HANDLE CurrentProcess; // eax
  BOOL result; // eax
  BOOL pbDebuggerPresent; // [esp+D0h] [ebp-Ch] 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有什么反调试的插件吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-23 01:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表