BUUCTF逆向的一些wp(3)

目录

java逆向解密

[GXYCTF2019]luck_guy

刮开有奖

[BJDCTF2020]JustRE

 简单注册器


java逆向解密

java的class文件,用jd-gui打开,是一个简单的程序

import java.util.ArrayList;
import java.util.Scanner;

public class Reverse {
  public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    System.out.println("Please input the flag );
    String str = s.next();
    System.out.println("Your input is );
    System.out.println(str);
    char[] stringArr = str.toCharArray();
    Encrypt(stringArr);
  }
  
  public static void Encrypt(char[] arr) {
    ArrayList<Integer> Resultlist = new ArrayList<>();
    for (int i = 0; i < arr.length; i++) {     //arr为flag
      int result = arr[i] + 64 ^ 0x20;        //对flag加密
      Resultlist.add(Integer.valueOf(result));//valueOf()函数用于返回指定对象的原始值
    } 
    int[] KEY = { 
        180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 
        133, 191, 134, 140, 129, 135, 191, 65 };
    ArrayList<Integer> KEYList = new ArrayList<>();
    for (int j = 0; j < KEY.length; j++)
      KEYList.add(Integer.valueOf(KEY[j])); 
    System.out.println("Result:");
    if (Resultlist.equals(KEYList)) {//判断KEYLIST与Resultlist是否相等
      System.out.println("Congratulations);
    } else {
      System.out.println("Error);
    } 
  }
}

没什么可以说的,会一点java再查一查不懂的函数就行,写了个python脚本

key = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
       133, 191, 134, 140, 129, 135, 191, 65]
flag = ''
for i in range(len(key)):
    flag += chr(key[i] - 64 ^ 0x20)
print(flag)

flag{This_is_the_flag_!}

[GXYCTF2019]luck_guy

查壳,64位elf无壳,放进IDA

先看看Strings window,发现字符串"OK, it's flag:",跟进根据交叉引用进入get_flag()函数

unsigned __int64 get_flag()
{
  unsigned int v0; // eax
  int i; // [rsp+4h] [rbp-3Ch]
  int j; // [rsp+8h] [rbp-38h]
  __int64 s; // [rsp+10h] [rbp-30h] BYREF
  char v5; // [rsp+18h] [rbp-28h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  v0 = time(0LL);
  srand(v0);
  for ( i = 0; i <= 4; ++i )
  {
    switch ( rand() % 200 )
    {
      case 1:
        puts("OK, it's flag:");
        memset(&s, 0, 0x28uLL);                 // 将s的地址置零
        strcat((char *)&s, f1);                 // f1= ' GXY{do_not_ '
        strcat((char *)&s, &f2);                // flag为f1+f2
        printf("%s", (const char *)&s);
        break;
      case 2:
        printf("Solar not like you");
        break;
      case 3:
        printf("Solar want a girlfriend");
        break;
      case 4:
        s = 7F666F6067756369;
        v5 = 0;
        strcat(&f2, (const char *)&s);          // f2赋初值
        break;
      case 5:
        for ( j = 0; j <= 7; ++j )              // f2加密
        {
          if ( j % 2 == 1 )
            *(&f2 + j) -= 2;
          else
            --*(&f2 + j);
        }
        break;
      default:
        puts("emmm,you can't find flag 23333");
        break;
    }
  }
  return __readfsqword(0x28u) ^ v6;
}

 从case1了解到flag是f1+f2,f1已知,f2未知

case4为f2赋初值,case5对f2进行转换

这个题有两个比较坑的地方,一是f2是小端序,二是这里的f2不能直接转换为字符串,数据0x7F超出了ASCII码的范围,会乱码。

写一个python脚本

f1 = 'GXY{do_not_'
f2 = [0x69, 0x63, 0x75, 0x67, 0x60, 0x6F, 0x66, 0x7F]
nm = ''
for i in range(8):
    if i % 2 == 1:
        nm += chr(f2[i] - 2)
    else:
        nm += chr(f2[i] - 1)
print(f1 + nm)

刮开有奖

运行程序,没有得到有用的信息

放进IDA里,查看main函数(WinMain函数),发现调用了DialogBoxParamA函数继续跟进没有特别的发现,就看了下其中的DialogFunc函数,再看到其中的GetDlgItemTextA函数(作用是获取对话框中的标题或文本)并结合题目提示得知String为所求flag。

INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
  const char *v4; // esi
  const char *v5; // edi
  int v7[2]; // [esp+8h] [ebp-20030h] BYREF
  int v8; // [esp+10h] [ebp-20028h]
  int v9; // [esp+14h] [ebp-20024h]
  int v10; // [esp+18h] [ebp-20020h]
  int v11; // [esp+1Ch] [ebp-2001Ch]
  int v12; // [esp+20h] [ebp-20018h]
  int v13; // [esp+24h] [ebp-20014h]
  int v14; // [esp+28h] [ebp-20010h]
  int v15; // [esp+2Ch] [ebp-2000Ch]
  int v16; // [esp+30h] [ebp-20008h]
  CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF
  char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF

  if ( a2 == 272 )
    return 1;
  if ( a2 != 273 )
    return 0;
  if ( (_WORD)a3 == 1001 )
  {
    memset(String, 0, 0xFFFFu);
    GetDlgItemTextA(hDlg, 1000, String, 0xFFFF);
    if ( strlen(String) == 8 )                  // 长度为8
    {
      v7[0] = 90;
      v7[1] = 74;
      v8 = 83;
      v9 = 69;
      v10 = 67;
      v11 = 97;
      v12 = 78;
      v13 = 72;
      v14 = 51;
      v15 = 110;
      v16 = 103;
      sub_4010F0((int)v7, 0, 10);
      memset(v18, 0, 0xFFFFu);                  // 初始化,v18值置零
      v18[0] = String[5];
      v18[2] = String[7];
      v18[1] = String[6];
      v4 = sub_401000((int)v18, strlen(v18));   // base64加密
      memset(v18, 0, 0xFFFFu);
      v18[1] = String[3];
      v18[0] = String[2];
      v18[2] = String[4];
      v5 = sub_401000((int)v18, strlen(v18));
      if ( String[0] == v7[0] + 34
        && String[1] == v10
        && 4 * String[2] - 141 == 3 * v8
        && String[3] / 4 == 2 * (v13 / 9)
        && !strcmp(v4, "ak1w")                  // 判定条件
        && !strcmp(v5, "V1Ax") )
      {
        MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);// 弹出对话框
      }
    }
    return 0;
  }
  if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
    return 0;
  EndDialog(hDlg, (unsigned __int16)a3);
  return 1;
}

整个函数的逻辑不难懂只要满足那个很长的if判定条件就行,主要是对sub_4010F0和sub_401000这两个函数功能的理解。sub_401000函数很好说,其中使用了base64加密的特征值,稍加验证就知道是base64加密,这里推荐一个IDA插件叫findcrypt可以查找并定位常见算法的特征值,也可以自己添加算法,很方便,教程网上有,限于篇幅不赘述。

sub_4010F0函数比较长,可以修改成c程序直接运行来得到结果。

int __cdecl sub_4010F0(int a1, int a2, int a3)//伪代码中的v7是一个有两个元素的数组
{                                             //但函数使用了他后十位的值,这是因为
                                              //v7到v16地址连续,可以当成一个数组看
                                              //即v7[11]={90,74,83,69,67,97,78,72,51,110,103}
  int result; // eax
  int i; // esi
  int v5; // ecx
  int v6; // edx

  result = a3;                                  // a3=10
  for ( i = a2; i <= a3; a2 = i )               // a2=0
  {
    v5 = 4 * i;
    v6 = *(_DWORD *)(4 * i + a1);               // a1=v7,v7[0] = 90,v7[1] = 74;
    if ( a2 < result && i < result )            //*(_DWORD *)(4 * i + a1)中(_DWORD *)
                                                //将(4 * i + a1)定义为双字型整数的地址
                                                //最外层的*即为取此地址上的数据
                                                //一个数据占四字节所以乘以四
                                                //v6=a1[i]
    {
      do
      {
        if ( v6 > *(_DWORD *)(a1 + 4 * result) )
        {
          if ( i >= result )
            break;
          ++i;
          *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
          if ( i >= result )
            break;
          while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = 4 * i;
          *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
        }
        --result;
      }
      while ( i < result );
    }
LABEL_13:
    *(_DWORD *)(a1 + 4 * result) = v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}

修改sub_4010F0函数直接得到String[0],String[1]

#include <stdio.h>
#include<string.h>

int  sub_4010F0(int a1[11], int a2, int a3)//伪代码中的v7是一个有两个元素的数组
{                                             //但函数使用了他后十位的值,这是因为
                                              //v7到v16地址连续,可以当成一个数组看
                                              //即v7[11]={90,74,83,69,67,97,78,72,51,110,103}
  int result; // eax
  int i; // esi
  int v5; // ecx
  int v6; // edx

  result = a3;                                  // a3=10
  for ( i = a2; i <= a3; a2 = i )               // a2=0
  {
    v5 = 4 * i;
    v6 = a1[i];               // a1=v7,v7[0] = 90,v7[1] = 74;
    if ( a2 < result && i < result )            //*(_DWORD *)(4 * i + a1)中(_DWORD *)
                                                //将(4 * i + a1)定义为双字型整数的地址
                                                //最外层的*即为取此地址上的数据
                                                //一个数据占四字节所以乘以四
                                                //v6=a1[i]
    {
      do
      {
        if ( v6 > a1[result]  )
        {
          if ( i >= result )
            break;
          ++i;
           a1[v5] = a1[result] ;
          if ( i >= result )
            break;
          while ( a1[i]  <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = 4 * i;
          a1[result]  =  a1[i];
        }
        --result;
      }
      while ( i < result );
    }
LABEL_13:
    a1[result] = v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}

int main(){
    int v7[11]={90,74,83,69,67,97,78,72,51,110,103};
    sub_4010F0(v7,0,10) ;
    printf("String[0]=%c\n",v7[0]+34);  //伪代码中String为字符串而v7为整型
    printf("String[1]=%c\n",v7[1]);     //输出String[0],String[1]                 
    return 0;
}

根据判断条件,v4('ak1w')解码得到'jMp',String[5]='j',String[6]='M',String[7]='p',v5('V1Ax')解码得到'WP1',String[2]='W',String[3]='P',String[4]='1',String[0]='U',String[1]='J'

flag{UJWP1jMp}

[BJDCTF2020]JustRE

运行一下,呵,没啥用(可能有用我也不懂)

32位,无壳

 放进IDA先看String Windows,发现"BJD{%d%d2069a45792d233ac}"比较特别,跟进查看,找到了调用他的函数

 

 看到一堆不懂的函数就先查了查,第二个sprintf函数将String赋值为BJD{1999902069a45792d233ac}感觉挺像flag的就试了试,最终得到

flag{1999902069a45792d233ac}

 简单注册器

apk文件,我用的是APKIDE

 项目名称为com.example.flag,应该有一个flag的java包,也确实找到了,其下的maile文件对应java的class文件,找到main类(MainActivity),再点击左上方java图形得到java源码。

package com.example.flag;

import android.text.Editable;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.TextView;

class MainActivity$1
  implements View.OnClickListener
{
  MainActivity$1(MainActivity paramMainActivity, EditText paramEditText, TextView paramTextView) {}
  
  public void onClick(View paramView)
  {
    int j = 1;
    paramView = this.val$editview.getText().toString();
    if ((paramView.length() != 32) || (paramView.charAt(31) != 'a') || (paramView.charAt(1) != 'b') || (paramView.charAt(0) + paramView.charAt(2) - 48 != 56)) {
      j = 0;
    }
    if (j == 1)//上方代码都没意义,有帮助的代码从这开始
    {
      paramView = "dd2940c04462b4dd7c450528835cca15".toCharArray();//对paramView赋值
                                                                   //并转为字符数组
      paramView[2] = ((char)(paramView[2] + paramView[3] - 50));
      paramView[4] = ((char)(paramView[2] + paramView[5] - 48));
      paramView[30] = ((char)(paramView[31] + paramView[9] - 48));
      paramView[14] = ((char)(paramView[27] + paramView[28] - 97));
      j = 0;
      for (;;)
      {
        if (j >= 16)//此if语句用来控制for循环的结束
        {
          paramView = String.valueOf(paramView);
          this.val$textview.setText("flag{" + paramView + "}");//得到flag
          return;
        }
        int i = paramView[(31 - j)];
        paramView[(31 - j)] = paramView[j];
        paramView[j] = i;
        j += 1;
      }
    }
    this.val$textview.setText("注册码错误");
  }
}

python脚本如下:

paramView = 'dd2940c04462b4dd7c450528835cca15'
paramView = list(paramView)# 转为列表
paramView[2] = chr((ord(paramView[2]) + ord(paramView[3]) - 50))
paramView[4] = chr((ord(paramView[2]) + ord(paramView[5]) - 48))
paramView[30] = chr(ord(paramView[31]) + ord(paramView[9]) - 48)
paramView[14] = chr(ord(paramView[27]) + ord(paramView[28]) - 97)
for j in range(16):
    i = paramView[(31 - j)]
    paramView[(31 - j)] = paramView[j]
    paramView[j] = i
paramView = ''.join(paramView)# 转为字符串
print("flag{"+paramView+"}")

 最终flag{59acc538825054c7de4b26440c0999dd}


新手一枚,如有错误,欢迎指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

∪v

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值