MoeCTF 2023 re-2


前言

MoeCTF 2023 re 第二篇


GUI

这道题是一道32位windows程序的题目
只需要找到加密函数和密文即可解密
在这里插入图片描述
在 Windows 编程里,窗口过程(Window Procedure)属于回调函数,它的作用是处理发送给窗口的各类消息。当用户与窗口交互(像点击按钮、关闭窗口等)或者系统有事件发生时,操作系统会把相应的消息发送给窗口,而窗口过程函数则会对这些消息进行处理。

WndClass.lpfnWndProc = sub_450CDF; 这行代码把 WndClass 结构体的 lpfnWndProc 成员设置为 sub_450CDF。这里的 sub_450CDF 应该是一个函数指针,它指向的函数就会作为窗口过程函数来处理窗口消息。

我们跟进去

__CheckForDebuggerJustMyCode(&unk_528026);
  if ( Msg > 0xF )//如果msg的值大于15
  {
    if ( Msg == 16 )//并且msg的值等于16
    {
      DestroyWindow(hWndParent);//调用 DestroyWindow 函数销毁父窗口 hWndParent
    }
    else
    {
      if ( Msg != 273 )//如果msg不等于273,则调用 DefWindowProcW 函数,将该消息交给默认的窗口过程处理
        return DefWindowProcW(hWndParent, Msg, wParam, lParam);
      if ( (unsigned __int16)wParam == 1 )//msg不等于16且等于273
      {
        DlgItem = GetDlgItem(hWndParent, 2);
        GetWindowTextW(DlgItem, String, 1024);
        sub_450C94(String);
        v13 = 0;
        sub_450A0A(v7, v8);//加密函数
        LOBYTE(v13) = 1;
        sub_450C94(a91);//a91是密文
        if ( (unsigned __int8)sub_4531AB(v7, v6) )
          MessageBoxW(hWndParent, Text, L"hint", 0);
        else
          MessageBoxW(hWndParent, L"Sorry, flag error.", L"hint", 0);//这里消息弹窗flag错误,说明加密函数在上方
        sub_4529B8(v6);
        LOBYTE(v13) = 0;
        sub_4529B8(v7);
        v13 = -1;
        sub_4529B8(v8);
      }
    }
  }
  else
  {
    switch ( Msg )
    {
      case 0xFu:
        hDC = BeginPaint(hWndParent, &Paint);
        hbr = CreateSolidBrush(0xFFFFFFu);
        FillRect(hDC, &Paint.rcPaint, hbr);
        DeleteObject(hbr);
        EndPaint(hWndParent, &Paint);
        break;
      case 1u:
        CreateWindowExW(0, L"STATIC", L"Please input flag:", 0x50000000u, 10, 10, 120, 20, hWndParent, 0, 0, 0);
        CreateWindowExW(0, L"EDIT", &word_4FE15C, 0x50800000u, 10, 40, 250, 30, hWndParent, (HMENU)2, 0, 0);
        CreateWindowExW(0, L"BUTTON", L"submit", 0x50000000u, 10, 80, 80, 30, hWndParent, (HMENU)1, 0, 0);
        break;
      case 2u:
        PostQuitMessage(0);
        break;
      default:
        return DefWindowProcW(hWndParent, Msg, wParam, lParam);
    }
  }
  return 0;
} 

这段代码是一个 Windows 典型的窗口消息处理函数(回调函数)

sub_450A0A(v7, v8)是加密函数
sub_450C94(a91)中的a91是密文

在这里插入图片描述
跟进去这两个看看,加密函数是-5之后异或,那解密函数先异或再加5

在这里插入图片描述
再看a91
在这里插入图片描述
exp:

str1 = [0x0F, 0x3E, 0x30, 0x27, 0x13,
        0x01, 0x7D, 0x70, 0x70, 0x03,
        0x7D, 0x38, 0x0E, 0x7A, 0x23,
        0x7C, 0x0B, 0x1A, 0x3C, 0x7D,
        0x39, 0x7F, 0x3C, 0x4D, 0x4D,
        0x4D, 0x29]

for i in str1:
    tmp = (i ^ 0x51) + 5
    print(chr(tmp), end='')

UPX!

在这里插入图片描述
64位加壳程序
在这里插入图片描述
砸壳
在这里插入图片描述
函数逻辑很简单,str[j]异或0x67 如果等于byte_140196000[j],那就是对的,所以跟进去byte_140196000[j]
在这里插入图片描述
这里把8,W,‘8’,‘5’这些转换为对应的ascii码值再换成16进制即可,注意8和‘8’是不一样的,8是0x08,‘8’是8转换为ascii码值之后对应的16进制

3 dup(‘F’) 这个的意思是有三个‘F’,那就是三个0x46

exp:

str1 = [ 0x0A, 0x08, 0x02, 0x04, 0x13, 0x01, 0x1C, 0x57, 0x0F, 0x38,
  0x1E, 0x57, 0x12, 0x38, 0x2C, 0x09, 0x57, 0x10, 0x38, 0x2F,
  0x57, 0x10, 0x38, 0x13, 0x08, 0x38, 0x35, 0x02, 0x11, 0x54,
  0x15, 0x14, 0x02, 0x38, 0x32, 0x37, 0x3F, 0x46, 0x46, 0x46,
  0x1A]

for i in str1:
    tmp = i ^ 0x67
    print(chr(tmp), end='')

ezandroid

apk逆向,而且还是个典型的迷宫游戏
找到MainActivity函数进去

在 Android 逆向分析中,理解 JNI 也是非常关键的,因为很多 Android 应用会使用 JNI 来隐藏关键逻辑和数据
在这里插入图片描述

在这里插入图片描述
flag长度是23

把apk文件变成zip文件进去找到so文件里面的JNI_Onload,用ida打开

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
有迷宫但是不知道迷宫怎么构建

在这里插入图片描述
找到sub_E80这个函数,看到了wasd,且sw上下是15,就是说上下移动下标会加减15(到下一行的同一位置),那就是列数是15,行数是120/15 = 9

迷宫:


@********
.********
#…*
.********.***
.*
.***.********
*******


这里我直接用python脚本跑出结果
在这里插入图片描述

@是起点,下标=行号15+列号=15+3=18
#是终点=行号
15+列号=3*15+8=53

exp:

from collections import deque

# 定义迷宫
maze = [
    "***************",
    "***@***********",
    "***.***********",
    "*...****#..****",
    "*.********.****",
    "*.****.....****",
    "*.****.********",
    "*......********",
    "***************"
]

# 定义方向和对应的字符
directions = [(-1, 0, 'w'), (1, 0, 's'), (0, -1, 'a'), (0, 1, 'd')]

# 获取迷宫的行数和列数
rows = len(maze)
cols = len(maze[0])

# 找到起始位置 @ 和目标位置 #
start_row, start_col = None, None
target_row, target_col = None, None
for i in range(rows):
    for j in range(cols):
        if maze[i][j] == '@':
            start_row = i
            start_col = j
        elif maze[i][j] == '#':
            target_row = i
            target_col = j

# 计算 # 的下标
target_index = target_row * cols + target_col
print(f"# 的下标是: {target_index}")

# 初始化队列和访问标记
queue = deque([(start_row, start_col, "", [start_row * cols + start_col])])
visited = [[False] * cols for _ in range(rows)]
visited[start_row][start_col] = True

while queue:
    current_row, current_col, path, index_list = queue.popleft()

    # 如果到达目标位置,输出路径和下标变化
    if current_row == target_row and current_col == target_col:
        print("找到路径:", path)
        print("下标变化:", index_list)
        break

    # 尝试四个方向的移动
    for dr, dc, dir_char in directions:
        new_row = current_row + dr
        new_col = current_col + dc
        new_index = new_row * cols + new_col

        # 检查新位置是否合法且未访问过
        if 0 <= new_row < rows and 0 <= new_col < cols and maze[new_row][new_col] != '*' and not visited[new_row][new_col]:
            visited[new_row][new_col] = True
            new_path = path + dir_char
            new_index_list = index_list + [new_index]
            queue.append((new_row, new_col, new_path, new_index_list))
else:
    print("未找到路径。")

SMC

SMC 是一种代码混淆技术,代码在运行时会修改自身以达到隐藏真实逻辑的目的
在这里插入图片描述
在这里插入图片描述

for 循环从 0 到 121,共循环 122 次。
*((_BYTE *)&loc_4014D0 + i) ^= 0x66u;:对从 loc_4014D0 地址开始的每个字节进行异或操作,异或密钥为 0x66。(_BYTE *)&loc_4014D0 + i 表示当前要处理的字节的地址,通过解引用操作符 * 对该地址的字节进行异或运算。

写个idapython patch一下

addr = 0x4014D0  
for i in range(122):
    b = get_bytes(addr + i, 1)
    idc.patch_byte(addr + i, ord(b) ^ 0x66)
print('ok')

这是解密之前的样子
在这里插入图片描述

执行命令
在这里插入图片描述
回到解密之后
在这里插入图片描述
选中这些标红的区域,先按c转化为代码,然后再摁按P生成函数,最后再摁F5反编译
在这里插入图片描述
找到密文
在这里插入图片描述
异或即可出答案

junk_code

这里考察了花指令(就是多余指令)

进入main函数,发现有两个判断函数
在这里插入图片描述
点进去查看发现反编译失败
在这里插入图片描述
点击0x4605D0回到汇编,发现有多余指令
在这里插入图片描述
选中(点击一下即可)00460612摁U再选中0E8h点击NOP进行填充
在这里插入图片描述
再回到0x4605D0,选中(点击一下即可),摁p生成函数
在这里插入图片描述
摁f5反编译即可进去看到正确函数,大致内容就是flag值ascii码减去5等于aHj表里面的值
在这里插入图片描述
在这里插入图片描述
点进去查看即可知道aHj表
在这里插入图片描述
另一半flag也是一样的,摁p生成函数f5反编译
在这里插入图片描述
这里是个异或
在这里插入图片描述
在这里插入图片描述
两段合在一起即可得出flag
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值