山东省“技能兴鲁”职业技能大赛 决赛 学生组 RE方向WP

解决了 3/4 xiaoming、esayRe、good-re(拿一血很高兴

文章目录

xiaoming

main函数找到二进制串。函数名可知为字符串转二进制,则直接将找到的二进制转为字符串即可得到flag
在这里插入图片描述

binary = "01100110 01101100 01100001 01100111 01111011 01100110 01100010 00110001 00111001 00110111 00110101 011"\
         "00101 00111001 01100011 00111001 00110011 00110010 00111000 00110000 00110111 01100110 00110111 001110"\
         "01 00110100 00111001 00110011 00111001 00110101 01100100 01100101 00110100 01100100 00110100 01100001 "\
         "01100010 00110011 00110001 01111101"

binary = binary.split(' ')
flag = ''.join([chr(int(i, 2)) for i in binary])
print(flag)
# flag{fb1975e9c932807f7949395de4d4ab31}

esayRe

很基础的异或加密,主要是有一个反调试需要过一下,还有一些花指令。

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  unsigned int v4; // [rsp+Ch] [rbp-44h]
  char s[56]; // [rsp+10h] [rbp-40h] BYREF
  unsigned __int64 v6; // [rsp+48h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  ((void (__fastcall *)(__int64, char **, char **))loc_11E9)(a1, a2, a3);
  puts("input your flag:");
  memset(s, 0, 0x30uLL);
  __isoc99_scanf("%32s", s);
  v4 = strlen(s);
  sub_1271(s, v4);
  if ( !memcmp(s, &unk_4040, dword_4020) )
    puts("Yes");
  else
    puts("No");
  return 0LL;
}

很清晰的结构,sub_1271为加密函数

__int64 __fastcall sub_1271(__int64 a1, int a2)
{
  __int64 result; // rax
  unsigned int i; // [rsp+18h] [rbp-4h]

  for ( i = 0; ; ++i )
  {
    result = i;
    if ( (int)i >= a2 )
      break;
    *(_BYTE *)((int)i + a1) ^= (unsigned __int8)(2 * i) | 1;
  }
  return result;
}

看一下反调试的地方loc_11E9
在这里插入图片描述
IDA分析中一些比较常见的花指令。格式形如

  1. jmp [addr]+1 ; jmp [addr]+2 也同理
    
  2. jz [addr]+1
    jnz [addr]+1 ;两个地址都相同,功能就相当于jmp
    

去除的方式就是选中[addr]所在的行,按D将指令解析为数据
在这里插入图片描述
这里的0xEB字节就是干扰IDA反编译的花指令

去除两个花指令就可以找到sys_ptrace函数,也就是反调试。
在这里插入图片描述
修改之后记得应用(Edit-Patch program-Apply patches to…)

第一种方案:可以直接把jnz short loc_1225 改为 jz short loc_1225 后就可以正确的动调拿到密文了(静态的密文是不对的,因为加密前还进行了修改)

第二种方案:把这个函数中所有的花指令都nop掉使IDA可以正确识别后,静态分析逆出明文。

总共有4处花指令需要修改(0x11F1, 0x120A, 0x1226, 0x126A)。完成后选中0x11E9至0x1270使用U设置为未定义后使用C解析为指令后在函数开始位置(0x11E9)使用P创建函数后再使用F5即可得到正确的伪C代码。

__int64 sub_11E9()
{
  __int64 result; // rax
  int i; // [rsp+0h] [rbp-4h]

  __asm { syscall; LINUX - sys_ptrace }
  for ( i = 0; ; ++i )
  {
    result = (unsigned int)dword_4020;
    if ( i >= dword_4020 )
      break;
    byte_4040[i] = ~(i ^ byte_4040[i]);
  }
  return result;
}

byte_4040就是密文。进行了异或,所以就可以编写脚本了

key = [0x98, 0x91, 0x99, 0x9C, 0x89, 0x84, 0xAB, 0x96, 0x94, 0x80, 0xBF, 0x84, 0xDA, 0xD9, 0x88, 0xB0, 0xAF, 0xB9, 0x97, 0xFA, 0xAC, 0xB2, 0xB0, 0xB5, 0xA3, 0xB6, 0xA4, 0xE2, 0xB5, 0xB7, 0xA1]

# key 处理
for i in range(len(key)):
    key[i] = ~(key[i] ^ i) & 0xff  # & 0xff是为了防止溢出

flag = ''
for i in range(len(key)):
       flag += chr(key[i] ^ (2 * i | 1))

print(flag)
# flag{u_are_g00d_at_1nstruct1on}

静态分析更便于理解,但比赛中使用动调会更加快捷。在过掉sys_ptrace后,在输入flag语句的后方和比较函数前打上断点。将密文提取后直接把我们输入的内容改为密文,经过加密后就可以得到明文。
在这里插入图片描述
修改明文可以使用python执行命令(Shift+F2调出或File-ScriptCommand)

脚本如下:

from ida_bytes import get_bytes,patch_bytes
start_addr = 0x7FFFFFFFDDD8
enc = [0x67, 0x6F, 0x64, 0x60, 0x72, 0x7E, 0x52, 0x6E, 0x63, 0x76, 0x4A, 0x70, 0x29, 0x2B, 0x79, 0x40, 0x40, 0x57, 0x7A, 0x16, 0x47, 0x58, 0x59, 0x5D, 0x44, 0x50, 0x41, 0x06, 0x56, 0x55, 0x40, 0xDF]
for i in range(len(enc)):
    patch_byte(start_addr+i, enc[i])

start_addr换为起始地址,enc换为要修改的数组。(运行后不会拿上修改掉,关掉页面才会更新)
在这里插入图片描述
修改后F9再次运行,停在比较函数前。再看一下s数组可以发现已经有flag
在这里插入图片描述
这个原理其实很简单,因为加密使用的是异或,有一个特性就是 x^y^y=x 一个数异或两次就会抵消。所以可以利用源程序中的加密函数作为解密函数,解出flag。同理,类似于RC4这种对称加密的方式也可以利用这样的手段去解决。

good-re

这题透露了考点信息,在IDA加载调式信息的时候把程序路径输出了,而程序路径的目录写明了考点信息。

在这里插入图片描述
可以知道这个有很大可能涉及到RC4Base64的变表

但这个题使用了很多花指令,IDA根本无法反编译。

而且这题在IDA中动调,十分不顺利,赛时一开始调IDA就无响应了。现在复盘时也是问题重重,不知道是不是我插件的问题。

在这里插入图片描述
在这里插入图片描述
一直反复弹这两个窗。知道的师傅希望可以指点一下。

所以我决定去使用我并不熟悉的Ollydbg

不知道是不是因为吾爱的插件太牛了,动调过程中十分顺利。

先来一波搜索
在这里插入图片描述
发现疑似base64编码的字符串,跳转后打个断点先。

在这里插入图片描述
动调的过程中的可以知道这个程序的大致流程

  1. 先输入key1flag
  2. 输入完毕后对key1进行检验(使用Base64变表
  3. 如果错误就输出Your key1 is wrong,wrong,wrong!!!!!!
  4. key正确后检验flag (使用RC4)
  5. 如果错误的话输出Emmmmmm……,You should learn the RC4 algorithm again!!!
  6. 正确就输出WOW!You really know the RC4 algorithm!!!

经过动调过程中,如果在去进行智能搜索,会发现base64的表变了。(暂时还没动调出是哪里改了表)在这里插入图片描述
用这个表去解刚刚拿到的base64密文就可以得到key

import base64

str1 = "capZLtfkLW0Q8CmQf+MaTCqgCaIyK1mQvY560WG/Kac="  # 解密

string1 = "ZlzY2+wuq5VA8mrnfF7DcNECKTSLv0XQHpsxtGW3iBbjPR/6kyh1oOaeIgU4dM9J"  # 更换的表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print(base64.b64decode(str1.translate(str.maketrans(string1, string2))))

# b'Sh@nD0ng_1s_@_ver9_n1c3_p2ovince'

用这个key继续去动调,可以找到最终flag密文和input密文比较的位置。

打上断点运行拿到密文,再通过明文加密后的内容异或上明文就可以得到RC4所生成的密钥流,将得到的密钥流去和flag密文进行异或就可以拿到flag了

在这里插入图片描述

在这里插入图片描述
因为并不知道ollydbg怎么提内存,所以直接复制文本,用脚本处理了一下

input_text = b'a' * 30
enc_input = b'\xb5\x86D+\xda\xb2\xa0Dv\xd2\xe7\n\x99Zz/\x1d\xa1\n\xa8\xe3\x8a\xad\xbe}}\xb6&\xf2g'
enc_flag = b'\xb2\x8bD-\xc0\x97\xf1zn\x83\xf34\x94\np+#\xb4\x03\xfa\xdd\x85\xff\xa8CN\x94\x7f\xb2{'
key = []

for i in range(len(enc_input)):
    key.append(input_text[i] ^ enc_input[i])

for i in range(len(key)):
    print(chr(key[i] ^ enc_flag[i]), end='')

# flag{D0_y0u_l1ke_th3_n3w_RC8!}

分析得不是很详细,欢迎补充!
downdowndown没啥头绪,希望有解出的师傅可以分享一下

  • 38
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值