首页
社区
课程
招聘
[原创]owasp level1-level3
发表于: 2023-10-24 11:49 11704

[原创]owasp level1-level3

2023-10-24 11:49
11704

这篇文章详细介绍了解决OWASP人员(Bernhard Mueller)发布的Android crackme程序(owasp uncrackable)的几种方法。

链接:https://pan.baidu.com/s/1VJ7Y3psWoSi5NnlOpaohEw
提取码:1234

owasp uncrackable 能够找到的安全机制:

Java层的反编译工具(Dalvik bytecode):

So层反编译程序:

动态二进制检测框架:

编译工具

使用Jadx反编译工具打开apk如下所示

来到MainActivity入口

image-20231024105859256

猜测会有root权限的检测工具,顺着这个猜测,我们可以有两种思路解决这个root检测

继续往下看

image-20231024105911197

我们进入a

image-20231024105925372

进入后,内容如下

image-20231024105932772

经过观察,发现如果成功返回equals(true),就能suceeful,由于没有涉及到so层(没看到native),所以我们直接在Java层进行代码分析

image-20231024105952256

手写一下伪代码

java

js实现上述java函数

image-20231024110009106

java

使用js完成java的功能

类如下

这个时候,我们综合之前的分析

可以写出java脚本

js脚本

跑出的结果是
image-20231024110050256

就是我们想要的flag

注意,此时并没有绕过root检测,就已经完成了分析过程,但为了尊重开发者,我们按照之前的两个思路进行解题

image-20231024110100715

smali文件丢到其他目录下,方便我们接下来使用AS导入

image-20231024110111305

丢到H盘,把smail修改该名字为src

image-20231024110121550

AS(Android Studio下面统称AS)导入smalidea-0.06.zip

image-20231024110130446

image-20231024110137854

导入后会提示重启AS

重启AS,然后开始进行下面修改

image-20231024110147513

如果没有找到smail Files 说明在第三步(AS(Android Studio下面统称AS)导入smalidea-0.06.zip)出错,错误原因可能是当前AS的版本太低(低于4.0)应该使用smalidea-0.05.zip或者是当前AS版本(高于4.0)较高,但导入了低版本的smalidea-0.05.zip

新建项目,导入文件smail文件

image-20231024110157275

Oncreate函数下断点

image-20231024110204244

运行如下

<img src="upload/attach/202310/940967_RFDNEHHANPPKYHD.png" alt="image-20231024110212864" style="zoom:50%;" />

这里是8980 使用adb 命令 转发本地端口

image-20231024110221959

设置远程调试

点击右上方 AddConfiguration ...

image-20231024110230719

点击Remote JVM Debug

image-20231024110238082

image-20231024110247462

设置端口8800和名字app1

选择设备,并开始调试

image-20231024110256360

由于root检测,远程调试无法进入OnCreated界面,所以选择直接看smaile源码

image-20231024110305138

思路是:直接在smail层绕过Rootdebug检测

来到smail代码层需要修改绕过(Root函数代码)代码如下

image-20231024110313031

修改完后使用killer重新编译一下

image-20231024110322603

安装apk到手机,显示已经没有root 检测窗口了

image-20231024110333005

这个时候可以开启动态调试了,如图

image-20231024110341761

按照这个思路,我们也可以直接跳转到登录成功的界面,修改的smail代码如下

image-20231024110349079

重新编译,无论输入什么都能成功登录

没什么好说的,直接hook一把梭

image-20231024110402301

速战速决

思路:绕过JAVA层的root 检测

image-20231024110410838

右键复制frida代码

image-20231024110422164

把代码丢到vscode一把梭

使用命令frida -U -l 11.js -f owasp.mstg.uncrackable2

image-20231024110434618

于是我们过了root检测

image-20231024110442546

image-20231024110452982

在使用JNInative层调用了bar函数,直接开始在so分析

image-20231024110504662

image-20231024110515722

soida中,然后查看左边的字符栏,输入关键字bar

image-20231024110522989

我们点进去,然后F5反汇编

image-20231024110530456

flag 直接出来

flag:Thanks for all the fish

题目难度变大

apk丢到JADX-GUI查看MainActivity界面

image-20231024110541120

简化一下界面如下

得到的信息

由于CRC校验和比较弱,我们也许能通过修改反编译得到的函数和native层中的函数,直接绕过所有安全的检测

三个检测root函数来检测设备是否可能存在root权限

image-20231024115227008

image-20231024110555164

unzip xxx.apk -d fileso(文件夹名),进行解压

丢到ida进行静态分析,结合jadx,会发现so层有个init函数对字符数组(由private static final String xorkey = "pizzapizzapizzapizzapizz"字符串得到字节数组)进行处理

image-20231024110605314

ida里面搜索Init

image-20231024110615116

反编译一下

image-20231024110625467

看到这里的思路是,能不能用动态ida调试查看一下,不过我们继续静态分析

这里介绍一下JNI调用Java方法的传参逻辑

frida脚本演示可能更加直观一些

根据上面的知识,我们在Java_sg_vantagepoint_uncrackable3_MainActivity_init(init),对传入参数的名字进行修改(选中参数,快捷键n

image-20231024110635396

因为传入的a3是我们在jadx看到的字节数组(pizzapizzapizzapizzapizz)

image-20231024110646233

所以result肯定和前面的字节数组(pizzapizzapizzapizzapizz)有关(具体情况目前不明朗)

思路中断不妨查看一下启动时的so时候的ELF文件,该部分执行程序启动时候的函数指针(JNI)

image-20231024110656618

image-20231024111830602

其中的.init_array里面sub_31B0的引起了注意,点击进入

image-20231024110705756

反编译

image-20231024110715246

大概意思是sub_30D0创建了一个线程,线程调用了sub_30D0来里面是否有fridaxpose检测

image-20231024110731235

绕过这个函数可以通过hook pthread_create来阻止进程的创建来进行绕过也可以通过hooksub_30D0进行绕过

在这里选择后者

这里先贴一下相关知识点

linker64 是 Android 64 位系统中的动态链接器,它负责加载和链接共享库,以及解析符号引用,使得程序能够正确执行。在 Android 系统中,linker64 是一个重要的组件,它在应用程序启动时被调用,负责加载应用程序所需的共享库,并建立共享库之间的依赖关系。

linker64 的主要功能包括:

在 Android 64 位系统中,init_array 一般会被 linker64 中的 call_array 函数调用。call_array 函数负责遍历共享库中的 init_array 段,并依次执行其中的函数指针所指向的初始化函数。它会在动态链接器加载共享库时被调用,确保在程序启动时执行这些初始化函数。

由于反调试函数(sub_30D0)启动线程是在init_array 中,而so层的init_array都是被linker64中的call_array调用,所以我们直接去Hooklinker64 call_array,在这之前需要动态调试so获得linker64 call_array的地址

image-20231024110741053

image-20231024110751007

image-20231024110838726

image-20231024110827803

点击OK

image-20231024110845019

弹出一个列表框,search搜素app的包名

image-20231024110850905

我们在右边的Module板块搜索我们在IDA之前找到的重要call或者so的关键字,会发现有时候根本搜索不到

image-20231024110859179

因为没有F9加载

原因如下

ida pro附加成功之后,会先调到其他so,比如libc.so这些,这个时候,需要先f9跳过,等没得跳之后,才需要执行jdb。

F9加载就行

搜索Module : linker64

image-20231024110904940

Module : linker64 下搜索call_array

image-20231024110924940

记录一下call_array地址0000007D68B58764减去linker64的基地址(7D68B38000) =00020764(偏移地址)

image-20231024110932115

开始编写fridaHook脚本

运行之后发现仍然存在检测,继续往下分析 native层的init函数

image-20231024110942230

我们查看sub_323C的调用次数以便把握Hook时机(选中函数后按下x查看引用次数)

image-20231024110948552

只调用了一次,由于sub_323C只在init函数中,init函数在apk启动(oncreate)才被调用,所以我们选择在libfool.so加载的时候进行Hooklibfoo.soapkjava层调用System.loadLibrary("foo")进行加载,调用的底层逻辑是通过libandroid_runtime.soandroid_dlopen_ext来加载的so

具体的调用逻辑如下:

需要注意的是,android_dlopen_ext函数是Android Runtime中的一个函数,用于加载动态链接库。它是通过JNI接口提供给应用程序使用的。在调用android_dlopen_ext函数之前,应用程序需要先加载libandroid_runtime.so,并通过JNI接口导入android_dlopen_ext函数。这样才能在Java层调用android_dlopen_ext函数,并实现加载libfoo.so的功能。

根据这些信息, 继续编写Frida脚本

开始过java层的root检测

image-20231024111001233

直接选择checkRoot1右键获取Frida脚本

image-20231024111012120

添加到我们的之前的脚本上,返回false

image-20231024111034939

简单概括一下,bar函数通过生成key1和字符串pizzapizzapizzapizzapizz进行异或来获取新的字符串,我们的思路就是hook生成key1函数(v6 = sub_10E0(v9);)得到key1,再和"pizzapizzapizzapizzapizz"进行异或

完整脚本如下

image-20231024111045694

分析结束

public void verify(View view) {
    String str;
    //获取输入框的字符串
    String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();
    AlertDialog create = new AlertDialog.Builder(this).create();
    //我们需要进入的地方
    if (a.a(obj)) {
        create.setTitle("Success!");
        str = "This is the correct secret.";
    } else {
        create.setTitle("Nope...");
        str = "That's not it. Try again.";
    }
    create.setMessage(str);
    // 设置对话框的按钮
    create.setButton(-3, "OK", new DialogInterface.OnClickListener() { // from class: sg.vantagepoint.uncrackable1.MainActivity.2
        @Override // android.content.DialogInterface.OnClickListener
        public void onClick(DialogInterface dialogInterface, int i) {
            dialogInterface.dismiss();
        }
    });
    // 显示对话框
    create.show();
}
public void verify(View view) {
    String str;
    //获取输入框的字符串
    String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();
    AlertDialog create = new AlertDialog.Builder(this).create();
    //我们需要进入的地方
    if (a.a(obj)) {
        create.setTitle("Success!");
        str = "This is the correct secret.";
    } else {
        create.setTitle("Nope...");
        str = "That's not it. Try again.";
    }
    create.setMessage(str);
    // 设置对话框的按钮
    create.setButton(-3, "OK", new DialogInterface.OnClickListener() { // from class: sg.vantagepoint.uncrackable1.MainActivity.2
        @Override // android.content.DialogInterface.OnClickListener
        public void onClick(DialogInterface dialogInterface, int i) {
            dialogInterface.dismiss();
        }
    });
    // 显示对话框
    create.show();
}
public class a {
    // 判断字符串是否与加密后的字符串相等
    public static boolean a(String str) {
        byte[] bArr;
        byte[] bArr2 = new byte[0];
        try {
            // 对字符串进行AES解密
            bArr = sg.vantagepoint.a.a.a(b("8d127684cbc37c17616d806cf50473cc"), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            // 打印AES解密错误信息
            Log.d("CodeCheck", "AES error:" + e.getMessage());
            bArr = bArr2;
        }
        // 判断解密后的字符串与给定字符串是否相等
        return str.equals(new String(bArr));
    }
    // 将字符串转换为字节数组
    public static byte[] b(String str) {
        int length = str.length();
        byte[] bArr = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            // 将字符串中的每两个字符转换为对应的字节
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
        return bArr;
    }
}
public class a {
    // 判断字符串是否与加密后的字符串相等
    public static boolean a(String str) {
        byte[] bArr;
        byte[] bArr2 = new byte[0];
        try {
            // 对字符串进行AES解密
            bArr = sg.vantagepoint.a.a.a(b("8d127684cbc37c17616d806cf50473cc"), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            // 打印AES解密错误信息
            Log.d("CodeCheck", "AES error:" + e.getMessage());
            bArr = bArr2;
        }
        // 判断解密后的字符串与给定字符串是否相等
        return str.equals(new String(bArr));
    }
    // 将字符串转换为字节数组
    public static byte[] b(String str) {
        int length = str.length();
        byte[] bArr = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            // 将字符串中的每两个字符转换为对应的字节
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
        return bArr;
    }
}
public static byte[] getdecode(String word){
    byte[] base64decodedBytes = Base64.getDecoder().decode(word);
    byte[] newbase64decodedBytes =Base64.getDecoder().decode(word);
    String strcode = new String(newbase64decodedBytes);
    System.out.println(strcode);
    System.out.println(newbase64decodedBytes);
 
    return base64decodedBytes;
}
public static byte[] getdecode(String word){
    byte[] base64decodedBytes = Base64.getDecoder().decode(word);
    byte[] newbase64decodedBytes =Base64.getDecoder().decode(word);
    String strcode = new String(newbase64decodedBytes);
    System.out.println(strcode);
    System.out.println(newbase64decodedBytes);
 
    return base64decodedBytes;
}
getBase64decode = function (){
  var encode = "5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=";
  let decrypted = atob(encode);
  //转成字节数组
  let base64decodedBytes = new Uint8Array(atob(encode).split('').map((char) => char.charCodeAt(0)));
  return base64decodedBytes;
 
}
getBase64decode = function (){
  var encode = "5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=";
  let decrypted = atob(encode);
  //转成字节数组
  let base64decodedBytes = new Uint8Array(atob(encode).split('').map((char) => char.charCodeAt(0)));
  return base64decodedBytes;
 
}
public static byte[] b(String str) {
int length = str.length();
byte[] bArr = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
    bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
}
return bArr;
}
public static byte[] b(String str) {
int length = str.length();
byte[] bArr = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
    bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
}
return bArr;
}
const byte = (x) => ((((x | 0) & 0xff) + 128) % 256) - 128;
//判断是否大小写
Judgment_capitalization = function (input){
    if ( 'A'<=input &&input <='Z'){
        return true;
    }
    else
        return false;
}
//判断是否小写
Determine_whether_to_lower  = function (input){
    if ( 'a'<=input &&input <='z'){
        return true;
    }
    else
        return false;
}
digit = function (input,radis) {
 
    try {
        if (!isNaN(parseInt(input))) {
            if (parseInt(input) < 10 && parseInt(input) > -1) {
                return parseInt(input) < parseInt(radis) ? parseInt(input) : -1;
            }
        }
    } catch (err) {
    }
    try {
        if (Judgment_capitalization(input)) {
            return input.charCodeAt(0) < radis + 'A'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'A'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
 
    }
    try {
        if (Determine_whether_to_lower(input)) {
            return input.charCodeAt(0) < radis + 'a'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'a'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
    }
 
}
b = function (paramString){
    var nlength  = paramString.length;
    //直接使用intarrybuffer
    var arrofByte = new Int8Array(nlength/2);
    for(var i=0;i<nlength;i+=2){
        arrofByte[i/2] = (byte)(((digit(paramString.charAt(i),16)<<4)+digit(paramString.charAt(i+1),16)));
    }
    return (arrofByte);
}
const byte = (x) => ((((x | 0) & 0xff) + 128) % 256) - 128;
//判断是否大小写
Judgment_capitalization = function (input){
    if ( 'A'<=input &&input <='Z'){
        return true;
    }
    else
        return false;
}
//判断是否小写
Determine_whether_to_lower  = function (input){
    if ( 'a'<=input &&input <='z'){
        return true;
    }
    else
        return false;
}
digit = function (input,radis) {
 
    try {
        if (!isNaN(parseInt(input))) {
            if (parseInt(input) < 10 && parseInt(input) > -1) {
                return parseInt(input) < parseInt(radis) ? parseInt(input) : -1;
            }
        }
    } catch (err) {
    }
    try {
        if (Judgment_capitalization(input)) {
            return input.charCodeAt(0) < radis + 'A'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'A'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
 
    }
    try {
        if (Determine_whether_to_lower(input)) {
            return input.charCodeAt(0) < radis + 'a'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'a'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
    }
 
}
b = function (paramString){
    var nlength  = paramString.length;
    //直接使用intarrybuffer
    var arrofByte = new Int8Array(nlength/2);
    for(var i=0;i<nlength;i+=2){
        arrofByte[i/2] = (byte)(((digit(paramString.charAt(i),16)<<4)+digit(paramString.charAt(i+1),16)));
    }
    return (arrofByte);
}
public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(2, secretKeySpec);
        return cipher.doFinal(bArr2);
    }
}
public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(2, secretKeySpec);
        return cipher.doFinal(bArr2);
    }
}
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;
 
public class AES128ECBwithPKCS7 {
     
    private static final String SECRET = "AES";
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";
     
    // Decrypts the given byte array using AES 128 ECB with PKCS7 padding
    public static String newaes256ECBPkcs7PaddingDecrypt(byte[] bArr, byte[] bArr2) throws Exception {
        String strbrr = new String(bArr);
        String strbrr2 = new String(bArr2);
         
        // Create a new instance of the Cipher class with the specified algorithm
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
         
        // Initialize the cipher in decryption mode with the secret key
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(bArr, SECRET));
         
        // Perform the decryption operation
        byte[] doFinal = cipher.doFinal(bArr2);
         
        // Convert the decrypted byte array to a string and return it
        return new String(doFinal);
    }
     
    // Converts a hexadecimal string to a byte array
    public static byte[] b(String str) {
        int length = str.length();
        byte[] bArr = new byte[length / 2];
         
        // Iterate over the hexadecimal string and convert each pair of characters to a byte
        for (int i = 0; i < length; i += 2) {
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
         
        // Print the byte array
        System.out.println(bArr);
         
        return bArr;
    }
     
    // Decodes a Base64-encoded string and returns the decoded byte array
    public static byte[] getdecode(String word) {
        byte[] base64decodedBytes = Base64.getDecoder().decode(word);
        byte[] newbase64decodedBytes = Base64.getDecoder().decode(word);
        String strcode = new String(newbase64decodedBytes);
         
        // Print the decoded string and byte array
        System.out.println(strcode);
        System.out.println(newbase64decodedBytes);
         
        return base64decodedBytes;
    }
     
    public static void main(String[] args) throws Exception {
        // Decrypt the given text using AES 128 ECB with PKCS7 padding
        String text = newaes256ECBPkcs7PaddingDecrypt(b("8d127684cbc37c17616d806cf50473cc"), getdecode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc="));
         
        // Print the decrypted text
        System.out.println(text);
    }
}
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;
 
public class AES128ECBwithPKCS7 {
     
    private static final String SECRET = "AES";
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";
     
    // Decrypts the given byte array using AES 128 ECB with PKCS7 padding
    public static String newaes256ECBPkcs7PaddingDecrypt(byte[] bArr, byte[] bArr2) throws Exception {
        String strbrr = new String(bArr);
        String strbrr2 = new String(bArr2);
         
        // Create a new instance of the Cipher class with the specified algorithm
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
         
        // Initialize the cipher in decryption mode with the secret key
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(bArr, SECRET));
         
        // Perform the decryption operation
        byte[] doFinal = cipher.doFinal(bArr2);
         
        // Convert the decrypted byte array to a string and return it
        return new String(doFinal);
    }
     
    // Converts a hexadecimal string to a byte array
    public static byte[] b(String str) {
        int length = str.length();
        byte[] bArr = new byte[length / 2];
         
        // Iterate over the hexadecimal string and convert each pair of characters to a byte
        for (int i = 0; i < length; i += 2) {
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
         
        // Print the byte array
        System.out.println(bArr);
         
        return bArr;
    }
     
    // Decodes a Base64-encoded string and returns the decoded byte array
    public static byte[] getdecode(String word) {
        byte[] base64decodedBytes = Base64.getDecoder().decode(word);
        byte[] newbase64decodedBytes = Base64.getDecoder().decode(word);
        String strcode = new String(newbase64decodedBytes);
         
        // Print the decoded string and byte array
        System.out.println(strcode);
        System.out.println(newbase64decodedBytes);
         
        return base64decodedBytes;
    }
     
    public static void main(String[] args) throws Exception {
        // Decrypt the given text using AES 128 ECB with PKCS7 padding
        String text = newaes256ECBPkcs7PaddingDecrypt(b("8d127684cbc37c17616d806cf50473cc"), getdecode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc="));
         
        // Print the decrypted text
        System.out.println(text);
    }
}
const CryptoJS = require('crypto-js')
 
//转化为byte
const base = require("./Crypted/Base64");
const byte = (x) => ((((x | 0) & 0xff) + 128) % 256) - 128;
 
//判断是否大小写
Judgment_capitalization = function (input){
    if ( 'A'<=input &&input <='Z'){
        return true;
    }
    else
        return false;
}
 
//判断是否小写
Determine_whether_to_lower  = function (input){
    if ( 'a'<=input &&input <='z'){
        return true;
    }
    else
        return false;
 
}
 
digit = function (input,radis) {
 
    try {
        if (!isNaN(parseInt(input))) {
            if (parseInt(input) < 10 && parseInt(input) > -1) {
                return parseInt(input) < parseInt(radis) ? parseInt(input) : -1;
            }
        }
 
    } catch (err) {
    }
    try {
        if (Judgment_capitalization(input)) {
            return input.charCodeAt(0) < radis + 'A'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'A'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
 
    }
    try {
        if (Determine_whether_to_lower(input)) {
            return input.charCodeAt(0) < radis + 'a'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'a'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
    }
 
}
b = function (paramString){
    var nlength  = paramString.length;
    //直接使用intarrybuffer
    var arrofByte = new Int8Array(nlength/2);
    for(var i=0;i<nlength;i+=2){
        arrofByte[i/2] = (byte)(((digit(paramString.charAt(i),16)<<4)+digit(paramString.charAt(i+1),16)));
    }
    return (arrofByte);
}
 
/**
 *@description:将string转为UTF-8格式signed char字节数组
 *
 */
function byteToString(arr) {
    if(typeof arr === 'string') {
        return arr;
    }
    var str = '',
        _arr = arr;
    for(var i = 0; i < _arr.length; i++) {
        var one = _arr[i].toString(2),
            v = one.match(/^1+?(?=0)/);
        if(v && one.length == 8) {
            var bytesLength = v[0].length;
            var store = _arr[i].toString(2).slice(7 - bytesLength);
            for(var st = 1; st < bytesLength; st++) {
                store += _arr[st + i].toString(2).slice(2);
            }
            str += String.fromCharCode(parseInt(store, 2));
            i += bytesLength - 1;
        } else {
            str += String.fromCharCode(_arr[i]);
        }
    }
    return str;
}
 
 
//网络传输
function stringToByte(str) {
    var len, c;
    len = str.length;
    var bytes = [];
    for(var i = 0; i < len; i++) {
        c = str.charCodeAt(i);
        if(c >= 0x010000 && c <= 0x10FFFF) {
            bytes.push(((c >> 18) & 0x07) | 0xF0);
            bytes.push(((c >> 12) & 0x3F) | 0x80);
            bytes.push(((c >> 6) & 0x3F) | 0x80);
            bytes.push((c & 0x3F) | 0x80);
        } else if(c >= 0x000800 && c <= 0x00FFFF) {
            bytes.push(((c >> 12) & 0x0F) | 0xE0);
            bytes.push(((c >> 6) & 0x3F) | 0x80);
            bytes.push((c & 0x3F) | 0x80);
        } else if(c >= 0x000080 && c <= 0x0007FF) {
            bytes.push(((c >> 6) & 0x1F) | 0xC0);
            bytes.push((c & 0x3F) | 0x80);
        } else {
            bytes.push(c & 0xFF);
        }
    }
    return new Int8Array(bytes);
}
getBase64decode = function (){
 
 
    var encode = "5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=";
    let decrypted = atob(encode);
    let base64decodedBytes = new Int8Array(atob(encode).split('').map((char) => char.charCodeAt(0)));
    // var bytedecode = new Int8Array(100)
    // bytedecode =stringToByte(decrypted);
    const  strbrr = String.fromCharCode.apply(null,base64decodedBytes);
 
    console.log(strbrr);
    return base64decodedBytes;
 
}
 
 
//AES_ECB模式解密
deCryptedByAes_ECB = function (data,AESkey){
    var  strdata = byteToString(data);
    var strAESKey = byteToString(AESkey)
    var key = CryptoJS.enc.Utf8.parse(AESkey);
    var decrypt = CryptoJS.AES.decrypt(data, key, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7,
    });
    return CryptoJS.enc.Utf8.stringify(decrypt).toString();
    把加密的内容和秘钥转化为wordarry对象
    // const encryptedwordarry = CryptoJS.enc.Hex.parse(data.join(''));
    // const keywordArry = CryptoJS.enc.Utf8.parse(AESkey.join(''));
    // //解密
    // const decrypted = CryptoJS.AES.decrypt(
    //     {ciphertext:encryptedwordarry},
    //     keywordArry,{mode:CryptoJS.mode.ECB,padding:CryptoJS.pad.Pkcs7}
    // )
    // return decrypted.toString(CryptoJS.enc.Utf8);
 
}
 
const  str = byteToString(b("8d127684cbc37c17616d806cf50473cc"))
 
gettext = function () {
    var text = deCryptedByAes_ECB(b("8d127684cbc37c17616d806cf50473cc"),getBase64decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc="))
    console.log(text);
}
 
console.log(gettext())
const CryptoJS = require('crypto-js')
 
//转化为byte
const base = require("./Crypted/Base64");
const byte = (x) => ((((x | 0) & 0xff) + 128) % 256) - 128;
 
//判断是否大小写
Judgment_capitalization = function (input){
    if ( 'A'<=input &&input <='Z'){
        return true;
    }
    else
        return false;
}
 
//判断是否小写
Determine_whether_to_lower  = function (input){
    if ( 'a'<=input &&input <='z'){
        return true;
    }
    else
        return false;
 
}
 
digit = function (input,radis) {
 
    try {
        if (!isNaN(parseInt(input))) {
            if (parseInt(input) < 10 && parseInt(input) > -1) {
                return parseInt(input) < parseInt(radis) ? parseInt(input) : -1;
            }
        }
 
    } catch (err) {
    }
    try {
        if (Judgment_capitalization(input)) {
            return input.charCodeAt(0) < radis + 'A'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'A'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
 
    }
    try {
        if (Determine_whether_to_lower(input)) {
            return input.charCodeAt(0) < radis + 'a'.charCodeAt(0) - 10 ? input.charCodeAt(0) - 'a'.charCodeAt(0) + 10 : -1;
        }
    } catch (err) {
    }
 
}
b = function (paramString){
    var nlength  = paramString.length;
    //直接使用intarrybuffer
    var arrofByte = new Int8Array(nlength/2);
    for(var i=0;i<nlength;i+=2){
        arrofByte[i/2] = (byte)(((digit(paramString.charAt(i),16)<<4)+digit(paramString.charAt(i+1),16)));
    }
    return (arrofByte);
}
 
/**
 *@description:将string转为UTF-8格式signed char字节数组
 *
 */
function byteToString(arr) {
    if(typeof arr === 'string') {
        return arr;
    }
    var str = '',
        _arr = arr;
    for(var i = 0; i < _arr.length; i++) {
        var one = _arr[i].toString(2),
            v = one.match(/^1+?(?=0)/);
        if(v && one.length == 8) {
            var bytesLength = v[0].length;
            var store = _arr[i].toString(2).slice(7 - bytesLength);
            for(var st = 1; st < bytesLength; st++) {
                store += _arr[st + i].toString(2).slice(2);
            }
            str += String.fromCharCode(parseInt(store, 2));
            i += bytesLength - 1;
        } else {
            str += String.fromCharCode(_arr[i]);
        }
    }
    return str;
}
 
 
//网络传输
function stringToByte(str) {
    var len, c;
    len = str.length;
    var bytes = [];
    for(var i = 0; i < len; i++) {
        c = str.charCodeAt(i);
        if(c >= 0x010000 && c <= 0x10FFFF) {
            bytes.push(((c >> 18) & 0x07) | 0xF0);
            bytes.push(((c >> 12) & 0x3F) | 0x80);
            bytes.push(((c >> 6) & 0x3F) | 0x80);
            bytes.push((c & 0x3F) | 0x80);
        } else if(c >= 0x000800 && c <= 0x00FFFF) {
            bytes.push(((c >> 12) & 0x0F) | 0xE0);
            bytes.push(((c >> 6) & 0x3F) | 0x80);
            bytes.push((c & 0x3F) | 0x80);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-10-24 11:56 被4Chan编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (6)
雪    币: 1429
活跃值: (1560)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark下。感觉大佬思路清晰
2023-10-25 11:07
0
雪    币: 2428
活跃值: (10698)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-10-27 09:12
0
雪    币: 478
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
其实没有必要用到ida的,第三题只要用frida枚举linker64的symbol,然后indexOf进行查找关键字就可以获得地址了
2023-11-24 11:22
0
雪    币: 376
活跃值: (2115)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
学到了
2023-11-28 22:22
0
雪    币: 657
活跃值: (5509)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2023-12-6 23:33
0
雪    币: 2161
活跃值: (4172)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
7
瀚总牛逼
2023-12-6 23:37
0
游客
登录 | 注册 方可回帖
返回
//