Jarvis OJ部分逆向

Jarvis OJ部分逆向题解

  很久没有写博客了,前天上Jarvis OJ刷了几道逆向,保持了一下感觉。都是简单题目,写个writeup记录一下。

easycrackme

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rdi
  char v5; // [rsp+0h] [rbp-38h]
  char v6; // [rsp+1h] [rbp-37h]
  char v7; // [rsp+2h] [rbp-36h]
  char v8; // [rsp+3h] [rbp-35h]
  char v9; // [rsp+4h] [rbp-34h]
  char v10; // [rsp+5h] [rbp-33h]
  unsigned __int8 v11; // [rsp+10h] [rbp-28h]
  _BYTE v12[7]; // [rsp+11h] [rbp-27h]

  v5 = -85;
  v6 = -35;
  v7 = 51;
  v8 = 84;
  v9 = 53;
  v10 = -17;
  printf((unsigned __int64)"Input your password:");
  _isoc99_scanf((unsigned __int64)"%s");
  if ( strlen((const char *)&v11) == 26 )       // 这里的strlen函数被去符号表解析了
  {
    v3 = 0LL;
    if ( (v11 ^ 0xAB) == list1 )                // 输入的第一个字母:"P",list1这里有关键数据
    {
      while ( (v12[v3] ^ (unsigned __int8)*(&v5 + ((signed int)v3 + 1) % 6)) == byte_6B41D1[v3] )
      {
        if ( ++v3 == 25 )
        {
          printf((unsigned __int64)"Congratulations!");
          return 0;
        }
      }
    }
  }
  printf((unsigned __int64)"Password Wrong!! Please try again.");
  return 0;
}

  静态分析找到代码,把byte_6841D1和list1那里的关键数据提取出来,直接逆向算法。

ch=[171,221,51,84,53,239]
list1=[0x9E,0x67,0x12,0x4E,0x9D,0x98,0xAB,0,6,0x46,0x8A,0xF4,0xB4,6,0x0B,0x43,0xDC,0xD9,0xA4,0x6C,0x31,0x74,0x9C,0xD2,0xA0]
print(len(list1))
temp,temp_ch=0,''
flag=''
flag+='P'
for i in range(25):
    temp=list1[i]^ch[(i+1)%6]
    temp_ch=chr(temp)
    print(temp_ch)
    flag+=temp_ch
print(flag)

 

 Baby's Crack

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  char Dest; // [rsp+20h] [rbp-80h]
  FILE *v5; // [rsp+88h] [rbp-18h]
  FILE *File; // [rsp+90h] [rbp-10h]
  char v7; // [rsp+9Fh] [rbp-1h]
  const char **v8; // [rsp+B8h] [rbp+18h]

  v8 = argv;
  if ( argc <= 1 )
  {
    printf("Usage: %s [FileName]\n", *argv, envp);
    printf("FileName是待加密的文件");
    exit(1);
  }
  File = fopen(argv[1], "rb+");
  if ( File )
  {
    v5 = fopen("tmp", "wb+");                   // v5是文件操作符
    while ( feof(File) == 0 )
    {
      v7 = fgetc(File);
      if ( v7 != -1 && v7 )                     // -1表示读取到文件末尾EOF
      {
        if ( v7 > 47 && v7 <= 96 )
        {
          v7 += 53;
        }
        else if ( v7 <= 46 )
        {
          v7 += v7 % 11;
        }
        else
        {
          v7 = 61 * (v7 / 61);
        }
        fputc(v7, v5);
      }
    }
    fclose(v5);
    fclose(File);
    sprintf(&Dest, "del %s", v8[1]);
    system(&Dest);
    sprintf(&Dest, "ren tmp %s", v8[1]);
    system(&Dest);
    result = 0;
  }
  else
  {
    printf("无法打开文件%s\n", v8[1]);
    result = -1;
  }
  return result;
}

  这里提供了flag的加密文件flag.enc,从关键代码这里来看,我们只要在字母表中找准对应的映射就可以了。脚本如下:

# -*- coding: utf-8 -*
import string
with open("C://Users//wolf//Desktop//babyscrack//flag.enc",'rb+') as f:
    flag_info=f.read()
print(flag_info)
def encrypto(a):
    if a!='\xff' and a:
        if ord(a)>47 and ord(a)<=96:
            a=chr(ord(a)+53)
        elif ord(a)<=46:
            a=chr(ord(a)+ord(a)%11)
        else:
            a=chr(61*(ord(a)/61))
    return a
enc='jeihjiiklwjnk{ljj{kflghhj{ilk{k{kij{ihlgkfkhkwhhjgly'
print(string.printable)
flag=""
for i in enc:
    for j in string.printable:
        if i==encrypto(j):
            flag+=j
            break
print(flag.decode('hex'))

stheasy

  这道题有一个小坑点在int8那里,表明是取后8位做抑或。

signed int __cdecl check(int a1)
{
  int v1; // eax
  int v3; // edx

  if ( a1 )
  {
    v1 = sub_804849C(a1);
    if ( v1 )
    {
      if ( v1 == 29 )
      {
        v3 = 0;
        while ( *(_BYTE *)(a1 + v3) == byte_8049AE0[(unsigned __int8)((unsigned __int8)byte_8049B15[v3] / 3u - 2)] )
        {
          if ( ++v3 == 29 )
            return 1;
        }
      }
    }
  }
  return 0;
}
s="k2j9Gh}AgfY4ds-a6QW1#k5ER_T[cvLbV7nOm3ZeX{CMt8SZo]U"
flag_info=[0x48,0x5D,0x8D,0x24,0x84,0x27,0x99,0x9F,0x54,0x18,0x1E,0x69,0x7E,0x33,
           0x15,0x72,0x8D,0x33,0x24,0x63,0x21,0x54,0x0C,0x78,0x78,0x78,0x78,0x78,0x1B]
print(len(flag_info))
print(len(s))
index,temp,flag,idx=0,"","",[]
for i in flag_info:
    temp=bin(i/3-2)
    if len(temp)>=10:
        temp=temp[-8:]
    else:
        temp=temp[2:]
    index=int(temp,2)
    idx.append(index)
for i in idx:
    flag+=s[i-1]
print(flag)

1.Hello

  这题有个反调试,但是不影响,静态分析就能出。start函数和dummy函数地址相减的地方注意一下,逻辑写正确即可。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  signed int v4; // [rsp+1Ch] [rbp-14h]
  int v5; // [rsp+24h] [rbp-Ch]

  v5 = ((unsigned __int64)((char *)start - (char *)dummy) >> 2) ^ flag_data[0];
  result = anti_debug();
  if ( !(result & 1) )
  {
    v4 = 0;
    while ( v4 < 55 )
    {
      flag_data[v4] -= 2;
      flag_data[v4] ^= v5;
      ++v4;
      ++v5;
    }
    result = printf("\nFinal output is %s\n", &flag_data[1]);
  }
  return result;
}
flag_data=[0x41, 0x10, 0x11,0x11,0x1B, 0x0A, 0x64, 0x67, 0x6A, 0x68,
            0x62, 0x68, 0x6E, 0x67, 0x68, 0x6B, 0x62, 0x3D, 0x65, 0x6A,0x6A,
            0x3D, 0x68, 0x4, 0x5, 0x8, 0x3, 0x2,0x2, 0x55, 8, 0x5D, 0x61, 0x55,
            0xA, 0x5F, 0x0D, 0x5D, 0x61, 0x32, 0x17, 0x1D, 0x19, 0x1F, 0x18,
            0x20, 0x4, 0x2, 0x12, 0x16, 0x1E, 0x54,0x20,0x13,0x14]
print(len(flag_data))
v5=((0xcb0-0xc90)>>2)^flag_data[0]
v4,flag=0,""
while(v4<55):
    flag_data[v4]-=2
    flag_data[v4]^=v5
    flag+=chr(flag_data[v4])
    v4+=1
    v5+=1
print(flag)

Classical Crackme

  这道题去了符号表,加了返混淆,好像还是C#写的,但是没关系,直接去找字符串常量,发现有一串字符串

Jarvis OJ部分逆向

 

   一看就是base64加密的,解密之后就是flag。

findkey

  这是一道python逆向的题目,直接用IDA看显示的就是字节码。在linux下用file查一下,发现应该是一个pyc,这时候用在线网站进行一步反汇编,拿到源码之后,逆向算法,exp如下所示。

lookup = [196,153,149,206,17,221,10,217,167,18,36,135,103,61,111,31,92,152,21,228,105,191,
        173,41,2,245,23,144,1,246,89,178,182,119,38,85,48,226,165,241,166,214,71,90,151,3,
        109,169,150,224,69,156,158,57,181,29,200,37,51,252,227,93,65,82,66,80,170,77,49,177,
        81,94,202,107,25,73,148,98,129,231,212,14,84,121,174,171,64,180,233,74,140,242,75,
        104,253,44,39,87,86,27,68,22,55,76,35,248,96,5,56,20,161,213,238,220,72,100,247,8,
        63,249,145,243,155,222,122,32,43,186,0,102,216,126,15,42,115,138,240,147,229,204,117,
        223,141,159,131,232,124,254,60,116,46,113,79,16,128,6,251,40,205,137,199,83,54,188,19,
        184,201,110,255,26,91,211,132,160,168,154,185,183,244,78,33,123,28,59,12,210,218,47,
        163,215,209,108,235,237,118,101,24,234,106,143,88,9,136,95,30,193,176,225,198,197,194,
        239,134,162,192,11,70,58,187,50,67,236,230,13,99,190,208,207,7,53,219,203,62,114,127,
        125,164,179,175,112,172,250,133,130,52,189,97,146,34,157,120,195,45,4,142,139]
pwda = [188,155,11,58,251,208,204,202,150,120,206,237,114,92,126,6,42]
pwdb = [53,222,230,35,67,248,226,216,17,209,32,2,181,200,171,60,108]

flag,temp="",0
for i in range(0,17):
    temp=lookup[i+pwdb[i]]-pwda[i]&255
    flag+=chr(temp)
flag=flag[::-1]
print(flag)

软件密码破解-1

  这道题肯定用strip把符号表全部都去掉了。静态分析的时候,修复符号表当然是一种思路,但是还是不够,我修复了大概7000个函数,还是很难找到关键代码,而且在IDA中找不到程序运行过程中出现过的一些字符串。这种时候,直接用OD的中文搜索引擎去找一些特殊的字符串,找到“你赢了”,然后很快地就可以定位到关键代码段。

Jarvis OJ部分逆向

 

   脚本如下。

array_1=[0x1b,0x1c,0x17,0x46,0xf4,0xfd,0x20,0x30,0xb7,0xc,0x8e,0x7e,0x78,0xDE]
array_2=[0xff,0x1a,0x4e,0xe4,0x53,0xe3,0x51,0x65,0x8f,0x93,0x6B,0x64,0x57,0x28]
array_2=array_2[::-1]
flag,temp="",0
for i in range(14):
    temp=array_1[i]^array_2[i]
    flag+=chr(temp)
print(flag)

 

 

上一篇:BUUCTF reverse2


下一篇:读懂操作系统(x64)之堆栈帧(过程调用)