【Android逆向】破解看雪9月算法破解第二题

android,逆向,破解,算法,第二 · 浏览次数 : 12

小编点评

The provided code implements a cryptographic function called `f` and several functions related to its operation. **`f` function:** - Takes arguments `B, C, D, t`. - Calculates the result of a complex logical operation involving `B, C, D` and `t`. - Depending on the value of `t`, it performs different logical combinations and returns the result. **`GETK` function:** - Takes an integer `t`. - Extracts different keys from the `K` array based on the value of `t`. - These keys are used in the `Step` function for encryption and decryption. **`Step` function:** - A global state `A, B, C, D, E` is maintained. - It calculates the first step of the encryption or decryption process based on the value of `t`. - The results of the calculation are updated in the state. **`GetCipher` function:** - Takes a cipher as input. - Extracts the key components (A, B, C, D, E) from the cipher. - Computes the first step of the encryption or decryption process for each key component. - Concatenates the results of these steps to generate the final cipher output. **`SHA1` function:** - Takes a context (m) and a cipher (cipher) as input. - Computes the SHA1 hash of the context. - Extracts the first 8 bytes of the hash as the final cipher output. **Example usage:** - The code can be used to encrypt a message and then display the encrypted text along with the hexadecimal representation of the encrypted message. - It can also be used to decrypt a previously encrypted message. **Note:** - The code uses various global variables and functions for encryption and decryption. - The specific values of the keys and the `Step` function's calculations depend on the algorithm being implemented.

正文

1. apk安装到手机,一样的界面,随便输入一样的报错

2. apk拖入到jadx重看看

public native String sha1(String str);

    static {
        System.loadLibrary("native-lib");
    }

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        this.edt_code = (EditText) findViewById(R.id.edt_code);
        this.edt_username = (EditText) findViewById(R.id.edt_username);
        Button button = (Button) findViewById(R.id.btn_register);
        this.btn_register = button;
        button.setOnClickListener(new View.OnClickListener() { // from class: com.r0ysue.sha1.MainActivity.1
            @Override // android.view.View.OnClickListener
            public void onClick(View view) {
                String obj = MainActivity.this.edt_username.getText().toString();
                if (MainActivity.this.sha1(obj).equals(MainActivity.this.edt_code.getText().toString())) {
                    Toast.makeText(MainActivity.this, "SUCCESS!", 0).show();
                } else {
                    Toast.makeText(MainActivity.this, "ERROR!", 0).show();
                }
            }
        });
    }

和第一题的套路一样,native方法名换成了sha1

3. 导出so,放入IDA中进行分析

jstring __fastcall Java_com_r0ysue_sha1_MainActivity_sha1(JNIEnv *env, jobject object, void *str)
{
  char *v4; // x20
  __int64 v5; // x23
  char *v6; // x20
  char v8[44]; // [xsp+4h] [xbp-7Ch] BYREF
  char v9[24]; // [xsp+30h] [xbp-50h] BYREF
  __int64 v10; // [xsp+48h] [xbp-38h]

  v10 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v4 = (char *)(*env)->GetStringUTFChars(env, str, 0LL);
  strlen(v4);
  sub_1BC0((int)v9, v4);
  v5 = 0LL;
  v6 = v8;
  do
  {
    sub_7E8(v6, -1LL);
    ++v5;
    v6 += 2;
  }
  while ( v5 != 20 );
  return (*env)->NewStringUTF(env, v8);
}

进入sub_1BC0中看看

__int64 __fastcall sub_1BC0(int a1, void *a2)
{
  __int128 v4; // [xsp+0h] [xbp-80h] BYREF
  __int64 v5; // [xsp+10h] [xbp-70h]
  int v6; // [xsp+18h] [xbp-68h]
  __int64 v7; // [xsp+68h] [xbp-18h]

  v7 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v4 = xmmword_1C50;
  v5 = 0xC3D2E1F0LL;
  v6 = 0;
  sub_19F0((int)&v4, a2);
  return sub_1AD4(a1, (int)&v4);
}

这个0xC3D2E1F0很眼熟,查了一些果然是sha1的特征初始化常量之一

sha1 初始化常量
A = 0x67452301
B = 0xEFCDAB89
C = 0x98BADCFE
D = 0x10325476
E = 0xC3D2E1F0

sha1 常量K
K = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6]
0≤t≤19  K = 0x5A827999
20≤t≤39 K = 0x6ED9EBA1
40≤t≤59 K = 0x8F1BBCDC
60≤t≤79 K = 0xCA62C1D6

既然已经找到了第一个,看看xmmword_1C50 会不会有所发现

0000000000001C50  01 23 45 67 89 AB CD EF  FE CC BA 98 76 54 32 10  .#Eg........vT2.

可以看到 这个数组对应的值,正好就是另外这个初始化变量的值(小端展示,需倒着看)
但是注意到有一个值是对应不上的 FE CC BA 98 76这里故意是将DC改成了CC, 所以相信直接用标准的Sha1算法计算出来的值,和这里的sha1算出来的值绝对是不一样的;

而在后续sub_19F0方法中我们找到了所有的K值,说明K是没有被魔改的

4. 编写frida看看,返回值是多少

function main() {
    Java.perform(function () {

        var MainActivityHandler = Java.use('com.r0ysue.sha1.MainActivity')

        console.log('1111')
        if (MainActivityHandler != undefined) {
            console.log('2222' )
            MainActivityHandler.sha1.implementation = function (str) {
                console.log('hooked src str = ' + str)
                var ret = this.sha1(str)
                console.log('hooked ret = ' + ret)

                return ret
            }
        }

    })

}

setTimeout(main, 1000)

日志

2222
hooked src str = abcd
hooked ret = 84fa69e00c65b500653e402ab42f9a2f26daa02c

通过在线sha1计算后的值是81fe8bfe87576c3ecb22426f8e57847382917acf

果然如我们所料,两个sha1的结果不一致

5. 编写python注册机,通过修改初始化常量值来匹配试试

#初始化变量
K = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6]
 
A = 0x67452301
B = 0xEFCDAB89
C = 0x98BACCFE
D = 0x10325476
E = 0xC3D2E1F0
 
A0 = 0x67452301
B0 = 0xEFCDAB89
C0 = 0x98BACCFE
D0 = 0x10325476
E0 = 0xC3D2E1F0
 
 
'''字节转换,字节(8bit)->字(32bit)'''
def CharToWord( context,i):
    return ((ord(context[i]) & 0x000000ff) << 24) | ((ord(context[i + 1]) & 0x000000ff) << 16) | ((ord(context[i + 2]) & 0x000000ff) << 8) | (ord(context[i + 3]) & 0x000000ff)
 
'''填充补位获得原始明文'''
def SHA1_fill(plaintext, group, length):
    print("补位后的明文:")
    text1 = list(plaintext)
    for n in range(length//8, 56):
        text1.append(chr(0))
    plaintext=''.join(text1)
    temp = length // 32
    len1 = length
    while len1 > 0:
        len1 = len1//32
        if len1:
            for j in range(0, temp):
                group[j] = CharToWord(plaintext, 4 * j)
                print(hex(group[j]))
        else:
            text = list(plaintext)
            b = 0x80
            text.insert(length // 8, chr(b))
            plaintext = ''.join(text)
            group[temp] = CharToWord(plaintext, temp * 4)
            print(hex(group[temp]))
            break
    group[15] = length
    for i in range(temp + 1,16):
        print(hex(group[i]).ljust(10, '0'))
 
 
'''f函数'''
def f(B ,C ,D , t):
    if t >=0 and t <= 19:
        return (B & C) ^ (~B & D)
    if t >= 20 and t <= 39:
        return B ^ C ^ D
    if t >= 40 and t <= 59:
        return (B & C) ^ (B & D) ^ (C & D)
    if t >= 60 and t <= 79:
        return B ^ C ^ D
 
 
'''获得 Kt'''
def GETK(t):
    if t >= 0 and t <= 19:
        return K[0]
    if t >= 20 and t <= 39:
        return K[1]
    if t >= 40 and t <= 59:
        return K[2]
    if t >= 60 and t <= 79:
        return K[3]
 
'''获得 Wt ,这里要特别注意mod(2**32)'''
def GETW(w):
    for i in range(16,80):
        w[i] = (((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) | ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31)) % 2**32
 
 
'''步函数,注意mod(2**32)'''
def Step(t,w):
    global A
    global B
    global C
    global D
    global E
    T = (((A << 5) | (A >> 27)) + f(B, C, D, t) + E + w[t] + GETK(t)) % 2**32
    E = D
    D = C
    C = ((B << 30) | (B >> 2)) % 2**32
    B = A
    A = T
 
 
'''获得密文'''
def GetCipher(cipher):
    cipher[0] = (A0 + A) % 2**32
    cipher[1] = (B0 + B) % 2**32
    cipher[2] = (C0 + C) % 2**32
    cipher[3] = (D0 + D) % 2**32
    cipher[4] = (E0 + E) % 2**32
    print("密文为:")
    for j in range(0, 5):
        print(hex(cipher[j])[2:], end='')
    print()
 
def SHA1(context, cipher):
    len1 = len(context) * 8
    group = []
    for i in range(80):
        group.append(0)
    SHA1_fill(context, group, len1)
    GETW(group)
    for t in range(80):
        Step(t, group)
    GetCipher(cipher)
 
 
 
 
m = input("请输入长度小于56的明文:")
c = []
for i in range(0, 5):
    c.append(0)
SHA1(m, c)
'''以下为python自带sha1函数,以便对照'''
import hashlib
print("自带函数哈希后密文:")
b = hashlib.sha1()
b.update(m.encode())
sha1 = b.hexdigest()
print(sha1)

日志

密文为:
84fa69e0c65b500653e402ab42f9a2f26daa02c
自带函数哈希后密文:
81fe8bfe87576c3ecb22426f8e57847382917acf

ok,成功对上,输入到手机爆破成功

与【Android逆向】破解看雪9月算法破解第二题相似的内容:

【Android逆向】破解看雪9月算法破解第二题

1. apk安装到手机,一样的界面,随便输入一样的报错 2. apk拖入到jadx重看看 public native String sha1(String str); static { System.loadLibrary("native-lib"); } /* JADX INFO: Access

【Android逆向】破解看雪9月算法破解第一题

1. 安装apk到手机 2. 随意输入账号和密码,点击register,报错crackme1:ERROR 3. 将apk拖入到jadx中进行观察 public native String register(String str); static { System.loadLibrary("nativ

【Android逆向】破解看雪9月算法破解第三题

这题的目标是算法还原,并写出注册机 1. 9月份算法第一题.apk 安装到手机 2. 随意输入账号密码,提示错误 3. apk拖入到jadx中 public native boolean register(String str, String str2); static { System.loadL

【Android逆向】破解看雪 test1.apk

1. 获取apk,并安装至手机 apk 获取地址: https://www.kanxue.com/work-task_read-800624.htm adb install -t test1.apk # 这个apk必须加-t ,否则会报错 2. 只有一个输入框,随便输入内容,提示壮士继续加油 3.

【Android逆向】破解看雪test3.apk方案一

1. test3.apk 安装到手机 2. 发现其实际逻辑和之前的test2.apk基本一致,逆向so查看到加入了一些检查逻辑 代码: jstring __fastcall fuck(JNIEnv *env, jclass jcls, jstring str_) { ...... if ( !str

【Android逆向】破解看雪test3.apk方案二

方案二就是要hook那三个条件,不让追加字符串变成false v20 = "REAL"; clazz = _JNIEnv::FindClass(env, "android/os/Build"); fieldID = _JNIEnv::GetStaticFieldID(env, clazz, "FIN

【Android逆向】破解黑宝宝apk,绕过签名校验

这是52pojie的一道题,实现输入任何密码都可以登录成功 他知道你最近在学习Android逆向 他想在游戏上线前让你测试一下他新加的签名验证是否能防住别人的破解。 下面是李华编写的黑宝宝apk 链接:https://pan.baidu.com/s/1h6pX2ARE3qtiKiYbcnJ-3g 密

【Android逆向】frida 破解 jwxdxnx02.apk

apk 路径: https://pan.baidu.com/s/1cUInoi 密码:07p9 这题比较简单,主要是用于练习frida 1. 安装apk到手机 需要输入账号密码 2. 使用jdax 查看apk package hfdcxy.com.myapplication; import andr

[Android逆向]Exposed 破解 jwxdxnx02.apk

使用exposed 遇到了一些坑,这里记录一下 源码: package com.example.exposedlesson01; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.X

[Android 逆向]frida 破解 切水果大战原版.apk

1. 手机安装该apk,运行,点击右上角礼物 提示 支付失败,请稍后重试 2. apk拖入到jadx中,待加载完毕后,搜素失败,找到疑似目标类MymmPay的关键方法payResultFalse 4. adb logcat 或者androidstudio 查看该进程的日志,发现以下日志 com.mf