初探Harmony逆向之so文件逆向分析篇
A1gorithms 发表于 安徽 技术文章 1086浏览 · 2024-11-18 09:16

初探Harmony逆向之so文件逆向分析篇

最近CTF鸿蒙逆向题出的频率还算高,本篇文章以蜀道山高校公益联赛上的HelloHarmony这题为核心来讲解一下Harmony逆向的so文件逆向分析
附件直接给了个Harmony系统的应用程序安装包.hap文件
直接改成zip进行解压拿到源码文件去反编译看逻辑
.abc文件就是Harmony的源码wen'j

程序反编译

编译工具还是用的jadx-gui-dev-all.jar
https://github.com/ohos-decompiler/abc-decompiler/releases


去Index里面看看


这里应该就是主逻辑了,可以看得出这是一个登录软件,账号直接给出来了


LZSDS

静态分析java层

那就是要逆密码了
我们看一下他获取我输入的密码做了哪些操作


(200 == testNapi.check(newobjrange.encrypt(_lexenv_01.password)) ? 1 : 0
newobjrange实际上是


可以在反编译出来的类里面看见


encrypt里面调用的是transform
transform则是一个魔改的凯撒,对大写字母的偏移是传参进来的5而小写字母则是5+2


那么newobjrange.encrypt(_lexenv_01.password)就分析完了,接下来就是看看testNapi.check()这个函数是做什么的
首先testNapi = import { default as testNapi } from "@normalized:Y&&&libentry.so&";
那么这个check实际上就是libentry.so里面的函数

分析SO文件

so文件在哪了?这里和安卓一样,安装包解压出来有个libs目录,so文件就在libs目录里面


拖入ida进行分析
通过字符串定位到check函数


深入分析函数
密钥扩展里面有两步操作,先是通过WTF::banana(this);初始化Sbox
再通过WTF::bananana(this, a2, a3);把key经过映射关系和或运算给Sbox


接下来分析Sbox和输入的密码进行的加密操作
WTF::heiheihei的传参则是Sbox,输入,存储结果的temp
加密经过8轮迭代,分析一下这8轮迭代做了什么


WTF::blablablablabla(Sbox, temp, i);函数进行的是一个异或操作,我刚开始分析的时候以为这个加密算法只对前8byte数据进行加密看完后面几个函数我就明白了。


WTF::bla(Sbox, temp);这里面则是一个映射操作


WTF::blablabla(Sbox, temp);函数则是对输入进行了一个循环左移的操作,这里面没用到Sbox


循环左移1位
到这里你应该就明白了,为什么不是只对前8byte的数据进行加密了,前8byte的数据经过循环移位会不断的变换位置,所以每一位都会经过异或处理

逆算法

那我们接下来的解密顺序则是
循环右移——>逆Sbox——>Xor
迭代数也要从7开始
Sbox怎么逆了?
Input[i] = Sbox[Input[i]]
加密里面是以Input[i]作为索引在Sbox里去取值的
也就是说索引就是Input[i]
写个Find去遍历索引即可


完整解密

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

void Init_Key(uint8_t* Sbox) {
    int i = 0;
    for (i = 0; i < 256; ++i) {
        Sbox[i] = (167 * i + 173) % 256;
    }
}

void GK(uint8_t* Sbox, char* key, int len) {
    int i = 0;
    for (i = 0; i < 8; ++i) {
        uint32_t key_chunk = key[(i + 3) % len] |
            (key[(i + 2) % len] << 8) |
            (key[(i + 1) % len] << 16) |
            (key[i % len] << 24);
        *((uint32_t*)Sbox + i + 64) = key_chunk;
    }
}

void GetKeyStream(uint8_t* Sbox, char* key, int len) {
    Init_Key(Sbox);
    GK(Sbox, key, len);
}

// 右移函数
void Right(uint8_t* enc) {
    uint8_t temp[40] = { 0 };
    int i;
    for (i = 0; i < 39; i++) {
        temp[i + 1] = enc[i];
    }
    temp[0] = enc[39];  
    memcpy(enc, temp, sizeof(temp));
}


int Find(uint8_t enc, uint8_t* Sbox) {
    int index = 0;
    for (index = 0; index < 256; index++) {
        if (enc == Sbox[index]) {
            return index;
        }
    }
    return -1;
}


void ReSbox(uint8_t* Sbox, uint8_t* enc) {
    int i;
    for (i = 0; i < 40; i++) {
        enc[i] = Find(enc[i], Sbox);
    }
}

void deXor(uint8_t* enc, uint8_t* Sbox, int i) {
    *((uint32_t*)enc) ^= *((uint32_t*)Sbox + i + 64);
    *((uint32_t*)enc + 1) ^= *((uint32_t*)Sbox + i + 64);
}


void Decrypt(uint8_t* Sbox, uint8_t* enc, int i) {
    Right(enc);
    ReSbox(Sbox, enc);
    deXor(enc, Sbox, i);
}

void CaesarDecrypt(uint8_t* text, int shift) {
    int i = 0;
    while (text[i] != '\0') {
        if (text[i] >= 'A' && text[i] <= 'Z') {
            text[i] = ((text[i] - 'A' - shift + 26) % 26) + 'A';
        }
        else if (text[i] >= 'a' && text[i] <= 'z') {

            text[i] = ((text[i] - 'a' - shift-2 + 26) % 26) + 'a';
        }

        i++;
    }
}


int main() {
    char key[] = "HelloSDS";
    uint8_t Sbox[256] = { 0 };
    uint8_t enc[40] = {
        0xF6, 0xB0, 0xA6, 0x36, 0x9A, 0xB3, 0x2B, 0xBF, 0x94, 0x54,
        0x15, 0x97, 0x93, 0x59, 0xBF, 0x50, 0x4D, 0xBF, 0x0A, 0x59,
        0x06, 0xD7, 0x97, 0x50, 0xD6, 0x59, 0x54, 0xD7, 0xCF, 0x06,
        0x5D, 0x20, 0x1D, 0x5A, 0x22, 0xEE, 0x99, 0x1F, 0xE1, 0x18
    };

    int i;
    int len = strlen(key);

    GetKeyStream(Sbox, key, len);


    for (i = 7; i >= 0; i--) {
        Decrypt(Sbox, enc, i);
    }
    CaesarDecrypt(enc, 5);

    puts((char*)enc);
    return 0;
}

//LZSDS{y0u_4r3_4_m4573r_0f_cryp706r4phy}

去用程序验证一下
依旧是使用DevEco Studio去模拟Harmony
把.hap文件直接拖进去即可安装


验证成功!
感谢师傅们的观看!

附件:
2 条评论
某人
表情
可输入 255