拓展知识:strncmp函数

reverse1

发送到exeinfope,可见无壳且为64位程序,所以IDA选择x64位
使用IDAx64打开之后,shift+f12跳转到字符串页面,关键语句“this is the right flag!\n”
通过交叉引用列表跳转到main函数,f5查看伪代码

先看输入(str1),char类型,用strncmp比较str1和str2。
如果str1和str2相等则返回0,取反之后输出this is the right flag!

点击str2,查看其值
回到伪代码,查看程序对str2操作,查询"111"和"48"对应的ascll码,可知这段代码是将"o",改为"0"

for ( j = 0; ; ++j )
{
v8 = j;
v2 = j_strlen(Str2);
if ( v8 > v2 )
  break;
if ( Str2[j] == 111 )
  Str2[j] = 48;
}

综合以上分析:flag{hell0,w0rld}

内涵的软件

发送到exeinfope,可见为32位程序
使用IDAx32位打开程序,shift+f12查看字符串,发现一段可疑代码(DBAPP{49d3c93df25caad81232130f3d2ebfad})
交叉引用跳到出现的函数,f5查看伪代码

貌似没什么有用信息,运行程序,输入"89",出现了一段提示(OD吾爱破解或者IDA这些逆向软件都挺好的)!
flag?提交不对。。。
把可疑代码提交上去。过了。

flag{49d3c93df25caad81232130f3d2ebfad}

-------2020/10/13-------

attachment_3

运行程序,随便输入
get_flag函数

载入到IDA,不难看出get_flag就是得到flag的函数。get_flag函数通过这个switch语句,先执行case5再执行case1就可以拿到flag,flag也就是s变量,由f1和f2构成,并且f1已知,只需要对f2进行操作即可。按照流程写解题代码。

f1='icug`of'
s=''
for i in range(0,8):
    if i%2==1:
        v1=ord(f1[i])-2;
    else:
        v1=ord(f1[i])-1;
    s+=chr(v1);
print('GXY{do_not_'+s);

-----2020/11/13-----

简单注册器


在模拟器中打开
载入到jadx-gui,找到判断注册码是否正确的地方

//关键处
char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
x[2] = (char) ((x[2] + x[3]) - 50);
x[4] = (char) ((x[2] + x[5]) - 48);
x[30] = (char) ((x[31] + x[9]) - 48);
x[14] = (char) ((x[27] + x[28]) - 97);
for (int i = 0; i < 16; i++) {
   char a = x[31 - i];
   x[31 - i] = x[i];
   x[i] = a;
}
textview.setText("flag{" + String.valueOf(x) + "}");

用Python跑一下

s='dd2940c04462b4dd7c450528835cca15'
x=[n for n in s]
x[2]=chr(ord(x[2])+ord(x[3])-50)
x[4]=chr(ord(x[2])+ord(x[5])-48)
x[30]=chr(ord(x[31])+ord(x[9])-48)
x[14]=chr(ord(x[27])+ord(x[28])-97)
for i in range(0,16):
    a=x[31-i]
    x[31-i]=x[i]
    x[i]=a
print("flag{" +''.join(x) + "}")

flag{59acc538825054c7de4b26440c0999dd}

-----2020/11/14-----

CrackRTF

这应该是我目前遇到最难的题目了,菜哭


0x0.无壳直接载入到IDA,f5查看main,到达main_0函数处,程序有两次输入,第一次输入正确才能进行下一次输入。

main_0函数
0x1.得到第一次输入的数值之后转化为字符串,然后和"@DBApp"拼接,再经过sub_40100A函数加密与"6E32D0943418C2C33385BC35A1470250DD8923A9"比较。
0x2.点进sub_40100A函数进入sub_401230函数,出现了一大堆看不懂的函数,百度一下发现CryptCreateHash和标识符0x8004是sha1加密。
0x3.注意到的是这里给出了整数的范围,可以使用hashlib库进行对比解密

import hashlib
s="@DBApp"
for i in range(100000,1000000):
    s1=str(i)+s
    n=hashlib.sha1(s1.encode('utf-8')).hexdigest()
    if n=="6E32D0943418C2C33385BC35A1470250DD8923A9".lower():
        q=i
        print(i,end=' ')
        break

sub_401230

0x4.第一次输入通过之后,进行第二次输入,第二次输入的数值和第一次拼接到一起。点击sub_401019函数进入函数sub_401040。通过0x8003标识可以看出是md5加密。
0x5.第二次输入没有范围,无法像第一次一样爆破,继续分析代码看到有个sub_40100F函数,进入这个函数发现了函数sub_4014D0
0x6.又出现了一大堆不认识的函数,通过百度和查看别人的wp大概理解了流程,使用FindResourceA函数从"AAA"资源中找0x65标识,找到之后通过SizeofResource函数获取资源大小,LoadResource函数获取资源第一次字节的指针。
0x7.然后通过sub_401005函数中的sub_401420函数,让资源数据和经过拼接的第二次输入的结构进行异或。

//sub_401420函数
unsigned int __cdecl sub_401420(LPCSTR lpString, int a2, int a3)
{
  unsigned int result; // eax
  unsigned int i; // [esp+4Ch] [ebp-Ch]
  unsigned int v5; // [esp+54h] [ebp-4h]

  v5 = lstrlenA(lpString);
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= a3 )
      break;
    *(_BYTE *)(i + a2) ^= lpString[i % v5];
  }
  return result;
}

sub_401040函数
sub_4014D0函数

0x8之后把异或的结果放到创建的dbapp.rtf里面。要想创建的rtf文件有意义,那么输入的数据里面必须包括rtk文件的信息,就像exe文件的pe头信息一样。
0x9.按照这个思路,我们创建一个rtf文件并且使用winhex打开。因为第二次输入的字符长度为6,所以我们选择前六个字符。

winhex内容
0x10.使用ResourceHacker打开flag文件,找到"AAA"资源依然取前六个字符。现在就可以写解密脚本了

ResourceHacker

import hashlib
s2="{\\rtf1"#\r转义成\\r
AAA=[0x05,0x7D,0x41,0x15,0x26,0x01]
flag2=''
for k in range(0,len(s2)):
    f=ord(s2[k])^AAA[k]
    flag2+=chr(f)
print(flag2)

第一次解密的结果为123321,第二次为~!3a@0,运行程序输入两次解密的结果,会在文件目录生成dbapp.rtf文件,flag就在里面。

----2020/11/16----

[BJDCTF2020]JustRE


载入到exeinfope,32位程序,无壳。

看起来这个程序需要点击到一定次数才可以得到flag
载入到IDA,查看字符串,发现了BJD{%d%d2069a45792d233ac},我们走到调用这个字符的__stdcall DialogFunc函数里面,可以看出当点击19999次才会出现flag。

__stdcall DialogFunc
拖到OD里面,CTRL+G到__stdcall DialogFunc函数处,查看汇编代码找到19999对应的十六进制0x4E1F处,直接将下面的 jnz short attachme.004013D0NOP掉。F9运行程序,小手一点flag到手。

__stdcall DialogFunc
结果
-----2020/11/17-----

2019红帽杯]easyRE


64位linux可执行程序,载入到IDA,通过字符串列表找到sub_400D35函数。

sub_400D35
通过分析可以看出这个函数有两次输入,第一次输入之后进行一次异或,第二次输入之后进行base64加密,对异或写脚本解出结果,base64找网上现成的网页界面一下

第一次输入异或之后进行对比的值

b=[ 73,111,100,108,62,81,110,98,40,111,99,121,127,121,46,105,127,100,
    96,51,119,125,119,101,107,57,123,105,121,61,126,121,76,64,69,67]
p=''
for n in range(0,36):
    p+=chr(b[n]^n);
print(p,end='')
#输出:Info:The first four chars are `flag`

base64解密出来是一个看雪论坛的帖子,没有什么有用信息。做到这里陷入了疑惑,有点懵逼了。去找了几个wp看了一下,原来关键函数是sub_400D35

sub_400D35函数

//关键判断处
if ( ((unsigned __int8)v5 ^ byte_6CC0A0[0]) == 'f' && (HIBYTE(v8) ^ (unsigned __int8)byte_6CC0A3) == 'g' )
  {
    for ( j = 0; j <= 24; ++j )
    {
      v2 = (unsigned __int8)(byte_6CC0A0[j] ^ *((_BYTE *)&v8 + j % 4));
      sub_410E90(v2);
    }
  }

if语句:v5和byte_6CC0A0[0]等于f,v8和byte_6CC0A3异或得g。for循环:byte_6CC0A0[j]和((_BYTE )&v8 + j % 4))。可以推测出v8应该是只有四个字符,并且前面已经知道到flag前四个值就是flag。可以由此异或出v8真正的值,并且得到flag,代码如下

a=[0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,
   0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]
s=['f','l','a','g']
flag=''
s2=''
print(p,end='')
for n in range(4):
    s2+=(chr(ord(s[n])^a[n]))
for n in range(0,25):
    flag+=(chr(ord(s2[n%4])^a[n]))
print(flag)
#v8=&YA1

-----2020/11/24--------

最后修改:2020 年 11 月 24 日
如果觉得我的文章对你有用,请随意赞赏