入门逆向

下载完成是一个baby.exe

image-20221231135840128

使用Exeinfo pe查下壳

image-20221231135915730

gcc编写 32位

拖入ida

image-20221231140311395

按两下 空格转换成 汇编模式

image-20221231142439063

选择66h 按R 即可转换成ascii

image-20221231142736761

flag{Re_1s_S0_C0OL}

从上图可以看到 _printf 的地址是 0x00401475

打开lcg 按住ctrl+G 搜索这个地址

image-20221231143704381

找到指令后按住 f12 下断点

image-20221231143805570

image-20221231145238137

可以看到 flag是从esp+0x2f开始的 拿计算器算一下

image-20221231145153656

61 FF1F

image-20221231145411391

image-20221231145433976

记得按 f8 步过和f7单步执行

image-20221231144315909

打开显示ascii数据

image-20221231145621699

signin

给了一个apk

image-20221231154518921

使用 jeb打开

image-20221231162249775

image-20221231162600597

这里可以看到 string 是在 0x7F0B0020 取出的

ctrl + f 直接搜索 发现该变量名字就是toString

image-20221231165417057

在string.xml下面找到 字符串的值

image-20221231165503357

我们对着源码 写下逆向函数

import base64

s= '991YiZWOz81ZhFjZfJXdwk3X1k2XzIXZIt3ZhxmZ'
s = s[::-1]
print(base64.b64decode(s))

image-20230102161110122

jeb动态调试

雷电模拟器开启 usb调试

image-20230101121533171

root权限

image-20230101121603979

使用androidkiller 添加debug

image-20221231182515371

加入 debug

android:debuggable="true"

image-20221231191405744

image-20221231191455873

image-20230102153442670

adb -s emulator-5554  install -r Sign_in_killer.apk

image-20230102153505890

image-20221231180233033

adb -s emulator-5554  shell am start -D -n re.sdnisc2018.sdnisc_apk1/.MainActivity

image-20230102153828698

image-20230102153848428

ctrl + B 添加断点

image-20230102153932433

查看变量类型需要将int 改为string

image-20230102154011912

Android Studio动态调试

image-20221231182232481

image-20221231182255583

image-20221231182310106

image-20230101121421995

image-20230102160015654

image-20230101121447907

adb shell am start -D -n re.sdnisc2018.sdnisc_apk1/.MainActivity

image-20230102160110157

image-20230102160132270

image-20230102160251473

image-20230102160305562

apk转jar

将apk重命名为zip 解压

image-20230102162245378

d2j-dex2jar.bat D:\Download\Sign_in_killer.apk\classes.dex -o  D:\Download\Sign_in_killer.apk\class.jar

image-20230102162425146

image-20230102162431648

image-20230102162507961

Timer(阿里CTF)

image-20230102163933147

jeb打开

image-20230102171239419

package net.bluelotus.tomorrow.easyandroid;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
int beg;
int k;
int now;
long t;

static {
System.loadLibrary("lhm");
}

public MainActivity() {
this.beg = ((int)(System.currentTimeMillis() / 1000L)) + 200000;
// 这里定义了 当前时间 并除1000 在加上20万
this.k = 0;
this.t = 0L;
}

public static boolean is2(int arg4) {
// arg4 是beg - now
if(arg4 <= 3) {
return arg4 > 1;
}

if(arg4 % 2 == 0 || arg4 % 3 == 0) {
// 如果 被2整除 或者被3整除 返回false
return false;
}

int i;
for(i = 5; i * i <= arg4; i += 6) {
if(arg4 % i == 0 || arg4 % (i + 2) == 0) {
return false;
}
}

return true;
}

@Override // android.support.v7.app.AppCompatActivity
protected void onCreate(Bundle arg7) {
super.onCreate(arg7);
this.setContentView(0x7F040018); // layout:activity_main
TextView tv1 = (TextView)this.findViewById(0x7F0C0050); // id:textView2
TextView tv2 = (TextView)this.findViewById(0x7F0C0051); // id:textView3
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
MainActivity.this.t = System.currentTimeMillis();
// 设置t为当前时间
MainActivity.this.now = (int)(MainActivity.this.t / 1000L);
// 设置now为当前时间除以1000
MainActivity.this.t = 1500L - MainActivity.this.t % 1000L;
// 设置t为 1500 - 当前时间 对1000取余
tv2.setText("AliCTF");
if(MainActivity.this.beg - MainActivity.this.now <= 0) {
// 如果beg - now <= 0
tv1.setText("The flag is:");
String v1 = "alictf{" + MainActivity.this.stringFromJNI2(MainActivity.this.k) + "}";
// stringFromJNI2 在最下面 是调用的本地二进制源文件 判断是否计算了正确的次数 也就是k的值
tv2.setText(v1);
}

if(MainActivity.is2(MainActivity.this.beg - MainActivity.this.now)) {
// 如果 is2 返回真
MainActivity.this.k += 100;
// k + 100
}
else {
--MainActivity.this.k;
// 否则 -1
}

tv1.setText("Time Remaining(s):" + (MainActivity.this.beg - MainActivity.this.now));
handler.postDelayed(this, MainActivity.this.t);
}
}, 0L);
}

@Override // android.app.Activity
public boolean onCreateOptionsMenu(Menu arg3) {
this.getMenuInflater().inflate(0x7F0D0000, arg3); // menu:menu_main
return true;
}

@Override // android.app.Activity
public boolean onOptionsItemSelected(MenuItem arg3) {
return arg3.getItemId() == 0x7F0C005F ? true : super.onOptionsItemSelected(arg3); // id:action_settings
}

public native String stringFromJNI2(int arg1) {
}
}


因此我们需要模拟k的值生成过程

public class Test {
public static void main(String[] args) {
int k = 0;
int n=0;
for (int i = 200000; i >0; i--) {
if (is2(i)) {
// 如果 is2 返回真
k += 100;
// k + 100
} else {
--k;
// 否则 -1
}



}
System.out.println(k);

}


public static boolean is2(int arg4) {
// arg4 是beg - now
if (arg4 <= 3) {
return arg4 > 1;
}

if (arg4 % 2 == 0 || arg4 % 3 == 0) {
// 如果 被2整除 或者被3整除 返回false
return false;
}

int i;
for (i = 5; i * i <= arg4; i += 6) {
if (arg4 % i == 0 || arg4 % (i + 2) == 0) {
return false;
}
}

return true;
}
}

image-20230102182409237

这里首先需要进入if 接着要 修改k的值

image-20230102184300464

image-20230102184941816

在下面添加

const v3, 1616384

image-20230102185157647

还需要修改 if语句

这里是如果v0 >0 就跳转到cond_0

image-20230102185626609

可以看到cond_0是else中的内容

image-20230102185727908

这里修改成lez

if-lez v0, :cond_0

image-20230102185758584

image-20230102185902326

image-20230102185943313

adb install -r .\Timer_killer.apk

image-20230102190032773

image-20230102190126391

mobile1(gctf)

简单读一下代码就知道 只需要输入 22个字符就可以出flag

image-20230102233019505

image-20230102233058976

image-20230102233140572

mobile2(gctf)

解压后是一个 这样的结构 可以发现是apk 先改名zip后解压之后的结果

image-20230103130359626

但是这里打开 发现是乱码 发现fl4g

image-20230103131245784

First_Mobile(xman)

去检查是否相等

image-20230103132958964

这里是encode类

image-20230103133038929



public class Test {
public static void main(String[] args) {
byte[] b = {23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 0x20, 0x20};
for (int i=0;i<16;++i){
for(int a=0;a<127;++a){
if (((a+b[i]) %61)*2 -i ==a){
System.out.print((char)a);
}

}
}


}


public class encode {
private static byte[] b;

static {
b = new byte[]{23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 0x20, 0x20};
// 静态赋值 b
}

public static boolean check(String str) {
byte[] input = str.getBytes();
// 将用户输入转化为byte
byte[] temp = new byte[16];

int i;
for(i = 0; i < 16; ++i) {
temp[i] = (byte)((input[i] + encode.b[i]) % 61);
// 将用户输入的每一个str + b 对61取余
}

int v0_1;
for(v0_1 = 0; v0_1 < 16; ++v0_1) {
temp[v0_1] = (byte)(temp[v0_1] * 2 - v0_1);
}

return new String(temp).equals(str);
}
}

}

image-20230103135017487

LoopAndLoop(阿里CTF)

image-20230103143819884

package net.bluelotus.tomorrow.easyandroid;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("lhm");
// System.loadLibrary("lhm"); 这里是java 的jni(java native interface)机制会用到的一个非常重要的函数
// 这里就是将加载lhm这个本地库 也就是lhm 中有一个chec方法 他有两个int参数 返回一个int值
}

public native int chec(int arg1, int arg2) {
// 这里是native层的 chec方法
}

public int check(int arg2, int arg3) {
return this.chec(arg2, arg3);
}

public int check1(int arg4, int arg5) {
int t = arg4;
int i;
for(i = 1; i < 100; ++i) {
// 这里的t就是 1到99的和
t += i;
}

return this.chec(t, arg5);
}

public int check2(int arg5, int arg6) {
int t = arg5;
if(arg6 % 2 == 0) {
// 如果 第二个参数被2整除
int i;
for(i = 1; i < 1000; ++i) {
// t 是1到999的和
t += i;
}

return this.chec(t, arg6);
}

int v0_1;
for(v0_1 = 1; v0_1 < 1000; ++v0_1) {
// t是1到999的差
t -= v0_1;
}

return this.chec(t, arg6);
}

public int check3(int arg4, int arg5) {
int t = arg4;
int i;
for(i = 1; i < 10000; ++i) {
// t是1到9999的和
t += i;
}

return this.chec(t, arg5);
}

public String messageMe(String arg3) {
// messagesMe是返回字符串 "LoopOk" + 参数
return "LoopOk" + arg3;
}

@Override // android.support.v7.app.AppCompatActivity
protected void onCreate(Bundle arg6) {
super.onCreate(arg6);
this.setContentView(0x7F040018); // layout:activity_main
// 这里两行用于调整布局
Button button = (Button)this.findViewById(0x7F0C0052); // id:button
TextView tv1 = (TextView)this.findViewById(0x7F0C0051); // id:textView2
TextView tv2 = (TextView)this.findViewById(0x7F0C0053); // id:textView3
button.setOnClickListener(new View.OnClickListener() {
@Override // android.view.View$OnClickListener
public void onClick(View v) {
//被点击时触发
int in_int = Integer.parseInt(((EditText)this.findViewById(0x7F0C0050)).getText().toString()); // id:editText
// 这里是获取我们输入的值 必须是一个int类型
if(MainActivity.this.check(in_int, 99) == 0x6D6F1462) {
// 如果输入的值在check 之后等于 0x6D6F1462
tv1.setText("The flag is:");
String v4 = "alictf{" + MainActivity.this.stringFromJNI2(in_int) + "}";
// 这里就调用本地的 stringFromJNI2 传入 in_int检查是否正确 并返回flag
tv2.setText(v4);
return;
}

tv1.setText("Not Right!");
}
});
}

@Override // android.app.Activity
public boolean onCreateOptionsMenu(Menu menu) {
this.getMenuInflater().inflate(0x7F0D0000, menu); // menu:menu_main
return true;
}

@Override // android.app.Activity
public boolean onOptionsItemSelected(MenuItem item) {
return item.getItemId() == 0x7F0C0061 ? true : super.onOptionsItemSelected(item); // id:action_settings
}

public native String stringFromJNI2(int arg1) {
}
}


简单分析一下就可以发现我们现在需要去 找本地链接库lhm文件

先将apk转换为zip 在解压即可 找到so文件

image-20230103144022611

在chec 可以发现关键代码

image-20230103155745161

int __fastcall Java_net_bluelotus_tomorrow_easyandroid_MainActivity_chec(int a1, int a2, int a3, int a4)
//可见这里传入了四个参数 其中a1 是jni接口指针 a2为对象和java类的引用 a3 a4 是我们传入的 java层参数 i和99
{
int v5; // r7
int result; // r0
int v10[9]; // [sp+1Ch] [bp-24h] BYREF

v5 = (*(int (__fastcall **)(int, const char *))(*(_DWORD *)a1 + 24))(
a1,
"net/bluelotus/tomorrow/easyandroid/MainActivity");
//这里代表的是 定义v5为一个 java MainActivity对象
v10[0] = _JNIEnv::GetMethodID(a1, v5, "check1", "(II)I");
//这里是获取java中的 check1 方法
v10[1] = _JNIEnv::GetMethodID(a1, v5, "check2", "(II)I");
v10[2] = _JNIEnv::GetMethodID(a1, v5, "check3", "(II)I");
if ( a4 - 1 <= 0 )
result = a3;
else
result = _JNIEnv::CallIntMethod(a1, a2, v10[2 * a4 % 3], a3, a4 - 1);
//这里可见调用了 CallIntMethod
return result;
}

image-20230103162214961

大致的意思就是根据 2 * a4 % 3 的值来决定调用哪一个check 比如a4是99因为这里的a4 是99 所以 2*99 %3 而后面的两个参数 是 调用 java层的 check(int arg2, int arg3) 的两个参数 在这里每次调用chec() 都会后一个参数都会减一

def chec(result, i):

while True:
if i == 100:
print(result)
return 0
if 2 * i % 3 == 0:
result, i =check0(result, i +1)
elif 2 * i % 3 == 1:
result, i =check1(result, i +1)

else:
result, i =check2(result, i+1)
def check0(result, i):
for t in range(1, 100):
result -= t
return result, i


def check1(result, i):
if i % 2 == 0:
for t in range(1, 1000):
result -= t
return result, i

for t in range(1, 1000):
result += t
return result, i


def check2(result, i):
for t in range(1, 10000):
result -= t

return result, i


result = 0x6D6F1462
chec(result,2)

这里要注意的是 循环的开始和结束的点

image-20230103175605407

image-20230103175720822

alictf{Jan6N100p3r}

SafeBox(NJCTF)

image-20230103190930462

可以发现有一个 Test包

image-20230103190958814

比较一下发现只是一个是3 一个是4

这里根本不用管原来的代码实在干啥直接爆破就可以

public class Test {
public static void main(String[] args) {
for (int i =10000000;i<=0x5F5E0FF;i++){
if(i > 10000000 && i < 0x5F5E0FF) {
int t = 1;
int t1 = 10000000;
int flag = 1;
if(Math.abs(i / 1000 % 100 - 36) == 3 && i % 1000 % 584 == 0) {
int j;
for(j = 0; j < 4; ++j) {
if(i / t % 10 != i / t1 % 10) {
flag = 0;
break;
}

t *= 10;
t1 /= 10;
}

if(flag == 1) {
System.out.println("NJCTF{" + ((char)(i / 1000000)) + ((char)(i / 10000 % 100)) + ((char)(i / 100 % 100)) + "f4n}");
}
}
}

}


}
}

image-20230103191739433

public class Test {
public static void main(String[] args) {
for (int i =10000000;i<=0x5F5E0FF;i++){
if(i > 10000000 && i < 0x5F5E0FF) {
int t = 1;
int t1 = 10000000;
int flag = 1;
if(Math.abs(i / 1000 % 100 - 36) == 3 && i % 1000 % 584 == 0) {
int j;
for(j = 0; j < 3; ++j) {
if(i / t % 10 != i / t1 % 10) {
flag = 0;
break;
}

t *= 10;
t1 /= 10;
}

if(flag == 1) {
System.out.println("NJCTF{have" + ((char)(i / 1000000)) + ((char)(i / 10000 % 100)) + ((char)(i / 100 % 100 + 10)) + "f4n}");
}
}
}

}


}
}

image-20230103191829909

HelloSmali2

image-20230103194833182

image-20230103194903723