Offensive and defensive world Android reverse practice

一.easy-so

1. jadx analysis program logic

You can see that the key lies in the cyberpeace.CheckString() function.
insert image description here
After double-clicking to follow up, you can find that it is a native layer function
insert image description here

2. ida view so file

Program logic:
1. Save the character string to the new space buffer
2. The first judgment is to exchange the first 16 characters and the last 16 characters of the buffer
3. The second judgment is to exchange the two adjacent characters of the buffer character swap position for

_BOOL8 __fastcall Java_com_testjava_jack_pingan2_cyberpeace_CheckString(__int64 a1, __int64 a2, __int64 a3)
{
    
    
  const char *str; // r14
  size_t len; // rax
  int len2; // r15d
  unsigned __int64 v6; // r12
  char *newMem; // rax
  char *buffer; // r13
  bool v9; // cc
  size_t v10; // r12
  size_t i; // rbx
  char tmp; // al
  char tmp1; // al
  size_t j; // rbx
  char tmp2; // al

  str = (*(*a1 + 1352LL))(a1, a3, 0LL);
  len = strlen(str);
  len2 = len;
  v6 = ((len << 32) + 0x100000000LL) >> 32;
  newMem = malloc(v6);
  buffer = newMem;
  v9 = v6 <= len2;
  v10 = v6 - len2;
  if ( v9 )
    v10 = 0LL;
  memset(&newMem[len2], 0, v10);
  memcpy(buffer, str, len2);
  if ( strlen(buffer) >= 2 )
  {
    
    
    i = 0LL;
    do
    {
    
    
      tmp = buffer[i];
      buffer[i] = buffer[i + 16];
      buffer[i++ + 16] = tmp;
    }
    while ( strlen(buffer) >> 1 > i );
    //32>>1 = 16 也就是说i<16时执行循环
  }
  tmp1 = *buffer;
  if ( *buffer )
  {
    
    
    *buffer = buffer[1];
    buffer[1] = tmp1;
    if ( strlen(buffer) >= 3 )
    {
    
    
      j = 2LL;
      do
      {
    
    
        tmp2 = buffer[j];
        buffer[j] = buffer[j + 1];
        buffer[j + 1] = tmp2;
        j += 2LL;
      }
      while ( strlen(buffer) > j );
    }
  }
  return strcmp(buffer, "f72c5a36569418a20907b55be5bf95ad") == 0;
}

Note that the disassembly results obtained by different so files are different.
At the beginning, I used the so files in the arm64-v8a folder to get this result, which is obviously wrong. This loop will lose some data at the end and then
insert image description here
open the x86_64 folder. so file is normal

3. Problem-solving script:

#include <stdio.h>
int main()
{
    
    
    char flag[33] = "f72c5a36569418a20907b55be5bf95ad";
    char tmp;
    for (int i = 0; i < 32; i += 2) // 两两交换
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 1];
        flag[i + 1] = tmp;
    }
    int i = 0;
    do
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 16];
        flag[i++ + 16] = tmp;
    } while (i<16);
    printf("flag{%s}",flag);
    //flag{90705bb55efb59da7fc2a5636549812a}
    return 0;
}

Two.ezjni

1. Program logic analysis

It can be seen that the string is also obtained and then encrypted
1. Obtain the string
2. Perform base64 encryption (the base table has been replaced)
3. Call the native function ncheck to judge the result
insert image description here
base64encode function, change the table base64 encryption:
insert image description here
ncheck function, here should be the same as the previous one The title easyso is the same operation, only due to decompilation errors
1. First exchange the first 16 characters and the last 16 characters
2. Then traverse from the beginning, and exchange positions for each group of two characters
insert image description here

2. Problem-solving script:

First output the base string before ncheck processing

#include <stdio.h>
int main()
{
    
    
    char flag[33] = "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7";
    char tmp;
    for (int i = 0; i < 32; i += 2) // 两两交换
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 1];
        flag[i + 1] = tmp;
    }
    int i = 0;
    do
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 16];
        flag[i++ + 16] = tmp;
    } while (i<16);
    printf("%s",flag);
    //QAoOQMPFks1BsB7cbM3TQsXg30i9g3==
    return 0;
}

First output the base64 table

public class test1{
    
    
    private static final char[] table = {
    
    'i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N'};

    public static void main(String[] args) {
    
    
        System.out.println("hello");
        String s="hellk";
        System.out.println(s);
        for (int i=0;i<table.length;i++)
        {
    
    
            System.out.print(table[i]);
            //i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN
        }
    }
}

Then use CyberChef to talk about it
insert image description here

Three. easyjava

1. Main function logic

This question basically has nothing to do with Android. It is mainly to analyze the java code logic. The
main function here calls a check method to judge the input flag,
insert image description here
and then look at the check method.
First judge the format of the flag{} at the beginning and end, and then get the characters in the curly braces
to create two The class is used for some subsequent processing
and then use the stringBuilder and func functions to create a new string.
Note that the func function passes in a single-character string each time, so each append adds a single character. The
insert image description here
func function
uses two functions Come to Matryoshka operation
insert image description here

2. getIndex function

First look at the index function (note that the function name and variable name here are manually modified according to the analysis). The
function logic here has been analyzed. First, determine whether the character is a letter, and then obtain the subscript of the character in str and
use the following Find the corresponding position in the array, then return the subscript in the array, and
finally use the change function to change the table (change is a circular left shift operation)
insert image description here

  1. array initialization
    insert image description here
  2. change function
    insert image description here

3. getChar function

This logic is relatively simple. It also checks the value in the table and then records the index, and searches the character in the table according to the index.
insert image description here

  1. list has similar operations to the previous function
    insert image description here

  2. judgeCount, since the characters are not as long as 25, this function is purely disturbing and makes people analyze more, it has no practical effect
    insert image description here

4. Problem-solving script

import java.util.ArrayList;
public class glass0{
    
    
    static String str = "abcdefghijklmnopqrstuvwxyz";
    static ArrayList<Integer> array = new ArrayList<>();
    static void change() {
    
    
        int value = array.get(0).intValue(); // 首个元素的int值
        array.remove(0); // 移除
        array.add(Integer.valueOf(value)); // 又加回去?
        str += "" + str.charAt(0);
        str = str.substring(1, 27); // 切割字符串并调整,左移一位的效果
    }
    public static void main(String[] args) {
    
    
        char[] flag="wigwrkaugala".toCharArray();
        String table = "abcdefghijklmnopqrstuvwxyz";
        int[] Table={
    
    7, 14, 16, 21, 4, 24, 25, 20, 5, 15, 9, 17, 6, 13, 3, 18, 12, 10, 19, 0, 22, 2, 11, 23, 1, 8};
        int[] intergerArr = {
    
    8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};
        ArrayList<Integer> list = new ArrayList<>();
        //初始化list
        for(int i=3;i<Table.length;i++){
    
    
            list.add(Table[i]);
        }
        for(int i=0;i<3;i++){
    
    
            list.add(Table[i]);
        }
        //初始化array
        for (int i = 2; i < intergerArr.length; i++) {
    
    
            array.add(intergerArr[i]); // 截取num~length后半段字符串
        }
        for (int j = 0; j < 2; j++) {
    
    
            array.add(intergerArr[j]); // 截取0~num-1前半段字符串
        }
        //开始解密
        for(int i=0;i<flag.length;i++){
    
    
            //获取下标值
            int index=table.indexOf(flag[i]);
            //获取num值
            int num=list.get(index);
            //这个num是getIndex函数的返回值
            int value=array.get(num);
            char chr=str.charAt(value);
            flag[i]=chr;
            change();
        }
        System.out.println(flag);//venividivkcr
    }
}

flag{venividivkcr}

4. APK Reverse

1. Program logic analysis

Detect the user name and the input SN code, the user name has been given here, so you can check the checkSN to checkSN and you can
insert image description here
see
that the SN code has 22 digits, and then perform md5 processing on the userName, and the hexadecimal string after md5 is every Take one every 2 digits, and then wrap it with flag{} to get the sn code you need
insert image description here

2. Problem-solving script

  1. to userNamemd5
  2. Take one for every 2 bits of the md5 result
import hashlib
text = "Tenshine"
hash_obj = hashlib.md5()
hash_obj.update(text.encode())
encrypted_text = hash_obj.hexdigest()
for i in range(0,len(encrypted_text),2):
    print(encrypted_text[i],end='')
#bc72f242a6af3857

flag:bc72f242a6af3857

3. Dynamic debugging

Use jeb to dynamically debug.
After setting a breakpoint, run the program and enter 22 characters to successfully break and see the value of the string.
insert image description here
jadx can also be debugged, but it doesn’t feel as silky as jeb
and the red is the variable value. At first glance I thought it was a mistake in the past...
insert image description here

Android2.0

The main function is to call the native function JNI.getResult.
insert image description here
The function of Init is to divide str into three segments and store them in three arrays, and then there are some XOR and comparison operations to solve the
insert image description here
problem script (note that the cycle is 0-3, not including the fifth character)

#include<stdio.h>
int main()
{
    
    
	unsigned char one[5] = "LN^dl";
	unsigned char two[5] = " 5-0a";
	two[3] = 0x16;
	unsigned char three[5] = "AFBo}";
	unsigned char flag[16] = {
    
     0 };
	for (int i = 0; i < 4; i++)
	{
    
    
		three[i] ^= two[i];
		two[i] ^= one[i];
		one[i] = (one[i] ^ 0x80) / 2;
		flag[i * 3] = one[i];
		flag[i * 3 + 1] = two[i];
		flag[i * 3 + 2] = three[i];
	}
	flag[12] = one[4];
	flag[13] = two[4];
	flag[14] = three[4];
	printf("%s",flag);
	return 0;
}

flag

In the name of the people - Capture Zhao Dehan 1-200

jar file, use jadx to open the analysis,
the main function first loads a checker object, and then calls the checkPassword method in the object to check whether the input password is correct. The
insert image description here
implementation of the loadCheckerObject method is given below, and you can see that it is AES decryption for the ClassEnc file. After decryption, return this class as the value of the loader method
. Note that the default AES decryption in the Java Cipher library is ECB mode, and the default padding method is PKCS5Padding , which is said to be a CBC mode pit by GPT.
insert image description here
Decryption script

import os
from Crypto.Cipher import AES
key=bytes().fromhex("bb27630cf264f8567d185008c10c3f96")
with open("ClassEnc","rb") as input: 
    data=input.read()
    cipher=AES.new(key,AES.MODE_ECB)
    decode= cipher.decrypt(data)
    
with open("ClassDec","wb") as out:
    out.write(decode)

input.close()
out.close()

Use jadx to open the decrypted ClassDec file.
You can find that the CheckPass class implements the checkPassword method of the CheckInterface interface
insert image description here
. A simple md5 can be decrypted online to get monkey99
, so many articles with flag {monkey99}
insert image description here
directly give the CheckPass method that comes with the jar package. However, according to the logic of the program, it is not called here. It may be that the author of the question forgot to delete this piece of code.
insert image description here

Reference article:

  1. JDK Security Module JCE Core Cipher Use Detailed Explanation
  2. Detailed explanation of Java JCE Cipher
  3. XCTF_MOBILE15_In the name of the people - Capture Zhao Dehan 1-200

app3

.ab file, chatgpt explains it like this:

通常情况下,.ab后缀的文件是Android应用程序备份文件,也称为“应用程序包文件”(.apk文件)的备份文件。
当您使用Android设备上的备份和重置功能时,系统将应用程序的数据和设置打包成一个.ab文件,以便稍后可以还原到设备上。
这些备份文件可以保存在本地存储设备或云存储中,以防意外数据丢失或设备更换。

There are two types of .ab: encrypted and unencrypted. If it is unencrypted, none will be displayed here.
insert image description here
Download and unpack the tool: android-backup-extractor
Note: This tool requires java11 and above to
use the command

java -jar abe.jar unpack 399649a0e89b46309dd5ae78ff96917a.ab app3.tar

insert image description here

insert image description here
Then the app3.tar compressed package will be output, and after decompression, you can find the apk file jadx in the folder to open the analysis logic

Guess you like

Origin blog.csdn.net/OrientalGlass/article/details/130913551