目录
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}
新手一枚,如有错误,欢迎指正。