duangsuse::Echo
719 subscribers
4.28K photos
130 videos
583 files
6.49K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
duangsuse::Echo
所有可以从 readelf -a liba.so 里找出有意思的信息: == ELF Header CLASS: ELF32 DATA: 2*, le VER: 1 OS/ABI: UNIX - SYSV (v0) TYPE: DYN ARCH: Intel 80386 (v1) == misc BuildID[sha1] = aa1eac616f2abab80d5b9268e955c0d37de0df26 GNU Gold: v1.1 == .symtab / .rel.plt / .dynsym…
那么我们就可以总结一下,逆向工程的进度:

== 这是一个 32 位 ELF 80386 共享对象文件,OS/ABI = UNIX/SysV、小端字序、包含调试信息
== BuildID(sha1): aa1eac616f2abab80d5b9268e955c0d37de0df26
== linker: GNU Gold v1.1

== 使用了 memcpy / memset / strlen / sprintf / strcmp / time / strcat 这些外部函数
== 导出了 BDL / BD / BEL / BE / bd / be | MI / MU / MF / me | r / Java_com_coolapk_market_util_AuthUtils_getAS 这些函数
== 需要 libdl.so / libstdc++.so / libc.so / libm.so / liblog.so 这些动态链接库
== 它的库名 (SONAME) 是 liba.so

== 我们真正想要的逻辑是调试符号中文件 a.c 里的 Java_com_coolapk_market_util_AuthUtils_getAS 函数

== FILE a.c (/Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/a.c)
- 这是 liba.so 的源文件名
- 经过调试符号检查,在 a.c 源文件里的函数:
r / Java_com_coolapk_market_util_AuthUtils_getAS
== FILE b.c (/jni/b.c)
- 这个文件应该是 Base64 算法的存放文件(从这里抄来的)
- 经过逻辑检查和调试符号信息排除,在 b.c 文件里的函数:
BDL / BD / BEL / BE / bd / be
- 还应该包含这两个对象:
static const char pr2six[256];
static const char b6[65
]; /* Radix64 + "\x00" */
== FILE m.c (/jni/c.c), /jni/m.h
- 这个文件应该存放了一些子程序定义
- 经过猜测,在预处理过程后 m.c 里的函数:
MI / MU / MF / me
- 还应该包含其他隐藏未导出的函数符号:
body

== 由 Android NDK Toolchain 自动生成的代码包括不限于以下符号,和逻辑没有一个半字的关系:
__x86.get_pc_thunk.bx = mov ebx, dword [esp]; ret
__atexit_handler_wrapper / __on_dlclose / atexit / __stack_chk_fail_local

== 编译工具链(Android GCC 4.9 Darwin) /Users/kjsolo/Library/Android/ndk/toolchains/x86-4.9/prebuilt/darwin-x86_64/lib/gcc/i686-linux-android/4.9/
== 平台(Android 21 x86) /ndk/platforms/android-21/arch-x86/usr/include/jni.h

现在找到在某 GitHub repo 里有主的函数(和对象)有这些:

extern static const unsigned char pr2six[256];
extern static const char b6[64 + /* C EOS */ 1];

extern static int BDL(const char *bufcoded); // Base64decode_len
extern static void BD(char *bufplain, const char *bufcoded); // Base64decode

extern static int BEL(int len); // Base64encode_len
extern static void BE(char *encoded, const char *string, int len); // Base64encode

extern static void bd(char *out, const char *in); // b64d after DCE (dead code elimination)
extern static void be(char *out, const char *str); // b64e after DCE
duangsuse::Echo
那么我们就可以总结一下,逆向工程的进度: == 这是一个 32 位 ELF 80386 共享对象文件,OS/ABI = UNIX/SysV、小端字序、包含调试信息 == BuildID(sha1): aa1eac616f2abab80d5b9268e955c0d37de0df26 == linker: GNU Gold v1.1 == 使用了 memcpy / memset / strlen / sprintf / strcmp / time / strcat 这些外部函数 == 导出了 BDL / BD…
顺带一提,有了被那位酷安大佬粗心忘记 strip 掉的调试符号的帮助,Avast 的 RetDec 反编译器瞬间黔驴变猛虎,生成了一大堆新的有用信息(正如我也菜 🐔 变病猫///)

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/a.c
// Address range: 0x1bc4 - 0x1bf0
// Line range: 27 - 30
void bd(char * dst, char * src);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/a.c
// Address range: 0x1ce9 - 0x1d2a
// Line range: 47 - 51
void be(char * dst, char * src);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/b.c
// Address range: 0x704 - 0x8e1
// Line range: 128 - 171
int32_t BD(char * bufplain, char * bufcoded);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/b.c
// Address range: 0x6a4 - 0x704
// Line range: 112 - 125
int32_t BDL(char * bufcoded);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/b.c
// Address range: 0x904 - 0xb26
// Line range: 184 - 214
int32_t BE(char * e, char * string, int32_t len);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/b.c
// Address range: 0x8e1 - 0x904
// Line range: 178 - 181
int32_t BEL(int32_t len);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/m.c
// Address range: 0xb2a - 0xc0e
// Line range: 93 - 116
char * body(int32_t ctx, char * data, int32_t size);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/a.c
// Address range: 0x1d2a - 0x24ee
// Line range: 53 - 145
char * Java_com_coolapk_market_util_AuthUtils_getAS(int32_t env, char * obj, char * entryObject, char * jstr);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/a.c
// Address range: 0x1bf0 - 0x1ce9
// Line range: 33 - 44
void me(char * dst, char * src);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/m.c
// Address range: 0x18be - 0x1b47
// Line range: 248 - 297
void MF(char * result, int32_t ctx);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/m.c
// Address range: 0x173a - 0x177a
// Line range: 201 - 210
void MI(int32_t ctx);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/m.c
// Address range: 0x177a - 0x18be
// Line range: 213 - 245
void MU(int32_t ctx, char * data, uint32_t size);

// From module: /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/a.c
// Address range: 0x1b47 - 0x1bc4
// Line range: 13 - 24
void r(char * s);
duangsuse::Echo
经过一点时间的努力和学习,把 base64.c 里的都对比一下酷安的生成算法里的符号 static const unsigned char pr2six[256]; 这是 一个类似 Threaded Interpretation 的优化表吧( 它就是 map 一个 char 所有可能的值到另一个 char,其实每次使用它 while (pr2six[*(bufin++)] <= 63); 这种,是用于优化编解码过程 具体的原理用途我不清楚,这里也没时间弄清楚。 radare2 is; 0x00002500;…
🤔 酷安 liba.so 添加了无用的依赖关系 liblog.so 使得在 GNU/Linux 电脑上动态链接失败无法正常工作,怎么办?
== readelf -d liba.so
== radare2 iS; seek 到 .dynamic 段,第一个依赖关系项 liblog 在 obj._DYNAMIC+69
CTF wiki 查到 DT_DEBUG 21(十六进制 0x15)一般工具不会管这种项目,而 NEEDED (0x1) 就会被 linker 视为必须的依赖库
o+ liba.so; v 模式,按一下 i 键输入 15,或者 w \x15 也行

(骗你们的)
实际上,这个项目在 obj._DYNAMIC+104
seek 到这个地址,然后 w \x15 就可以让 dynamic linker 直接忽视掉这个死依赖了。

[DuangSUSE@duangsuse]~/Projects/HackingCoolApk/liba% readelf -d liba.so
0x00000015 (DEBUG) 0xd7
0x00000001 (NEEDED) 共享库:[libstdc++.so]
0x00000001 (NEEDED) 共享库:[libm.so]
0x00000001 (NEEDED) 共享库:[libc.so]
0x00000001 (NEEDED) 共享库:[libdl.so]


🤔 酷安 liba.so 的 JNI 导出添加了包名校验逻辑,怎么办?
== 删掉就好。(滑稽)

🤔我该如何使用这个库文件?
动态链接加载使用。

🤔既然已经知道了这么多,为什么不完全重写 liba.so 呢?
没时间、技能不够熟练,壮士可以去(
我也想有源代码的直接复制粘贴,没源代码的上反汇编,可是这相当麻烦(要考虑一些重定位的问题和一些窥孔优化寄存器分配冲突的问题,所以必须要 inline assembly,我不想管那些也不想把汇编再拿 GCC 那蹩脚的汇编模板重写一遍),不如直接用成品,反正也不太差,符合工程规范(滑稽)。

就目前而言,反汇编主要用于软件分析,至于完全逆向工程然后重写算法什么的... 基本都是一些高级 native 编译器工程师的工作吧。
想直接拿 C 什么的重写(甚至只是一部分),没那么容易

反正我的目的就是让 x86-compat Linux 机也可以生成酷安的令牌,不是 Android 的专利
coolapk-liba-RE.zip
16.7 KB
#reveng #code #share 一些杂乱的代码 snippets 分享
coolapk-liba-ldload-RE.zip
20.7 KB
更新了一下,暂时没有解决 invalid header 的问题,睡觉... 🤔
看来区区一个在 GDB 里没有源代码就没有用的 DWARF 调试符号,对于逆向工程就有这么大的信息量... 🤔 忘记 strip 掉居然就暴露了这么多信息啊....
duangsuse::Echo
看来区区一个在 GDB 里没有源代码就没有用的 DWARF 调试符号,对于逆向工程就有这么大的信息量... 🤔 忘记 strip 掉居然就暴露了这么多信息啊....
酷安这位老哥保留的调试符号再次车祸现场暴露了第二个惊人但是不出我意料之外的信息:m.c 和 m.h 保存的是 MD5 算法(我早猜到过这种可能了,他们重命名就是这个尿性,要是我肯定就拿宏定义换成完全无意义的名字了) 😂


    <203>   DW_AT_name        : (indirect string, offset: 0x1af): /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/m.c

<1><228>:缩写编号:4 (DW_TAG_typedef)
<229> DW_AT_name : (indirect string, offset: 0x1f7): MD5_u32plus
<22d> DW_AT_decl_file : 2
<22e> DW_AT_decl_line : 32
<22f> DW_AT_type : <0x21a>


那么,你们看,调试符号真的是罪过啊,现在我的逆向工程量就缩小到 a.c (还是调试符号给的提示,让我知道开始编译时哪些函数是位于哪些文件)里的

// CoolLibrary/app/src/main/jni/a.c:53-145
char *Java_com_coolapk_market_util_AuthUtils_getAS(size_t env, char *obj, char *entryObject, char *jstr);

// CoolLibrary/app/src/main/jni/a.c:27-30
// b64d like wrapper
void bd(char *out, const char *code_str);

// CoolLibrary/app/src/main/jni/a.c:47-51
// b64e like wrapper
void be(char *dst, const char *src);

// CoolLibrary/app/src/main/jni/a.c:33-44
void me(char *dst, char *src);

// CoolLibrary/app/src/main/jni/a.c:13-24
void r(char *s);

这几个函数了,而它们失去了对『MD5、Base64』函数的用途依赖(我们现在知道它所用到一些真正复杂算法的外部逻辑究竟是在做什么),都很短,很容易拿 C 重写出整个算法。

以后开发想『保密』的 native 环境算法,千万不要忘记 strip 掉调试符号啊 🤪
duangsuse::Echo
酷安这位老哥保留的调试符号再次车祸现场暴露了第二个惊人但是不出我意料之外的信息:m.c 和 m.h 保存的是 MD5 算法(我早猜到过这种可能了,他们重命名就是这个尿性,要是我肯定就拿宏定义换成完全无意义的名字了) 😂 <203> DW_AT_name : (indirect string, offset: 0x1af): /Users/kjsolo/StudioProjects/CoolLibrary/app/src/main/jni/m.c <1><228>:缩写编号:4…
现在我甚至都不需要『花力气』多学点汇编和编译器技术了,因为 liba.so 真正自己(而不是抄的)的『业务逻辑』代码只有 51 行而已,我完全可以看反汇编,利用 base64.cboost:Uuid::detail::MD5 的部分外部库源代码完全还原出本来的生成逻辑,也可以拿 Ruby、Python、JavaScript 什么的彻底重写还原原逻辑,根本不需要再反汇编、重新汇编、转换对象格式、修改二进制对象文件结构什么的。

而且都不需要我检查反汇编代码来确认那些外部库的函数是否真的找到匹配的了,因为调试符号已经给出了所有需要的信息... 🤔

这两天进度飞快的逆向工程过程中,忘记 strip 掉的调试符号给了太多帮助,调试符号暴露了太多信息,甚至连函数、结构体的原型都可以从调试符号里面拿出来... 标识符,他们的名字也都直接从调试符号里取... 甚至哪个函数在哪个文件里,用了哪些开源代码,CoolApk 里面这个客户端库的内部名称叫什么,开发者的昵称是什么,用的什么操作系统,什么编译器... 全都知道了,所有人都知道了。

....

写编译配置的这位 dalao,NB 了。 👊
coolapk_a.zip
9.1 KB
😆 准备开始阅读反汇编完成 liba 的实际算法逻辑(是的,彻底的 C 重写!好耶)
开始了真正字面意义上的逆向工程 — 逆向分析和软件工程结合
coolapk_a_kdev.zip
136.9 KB
有了 Radare2 的自动分析和这么多外部库函数的定义,完全逆向工程出等价的程序逻辑变得不再困难,甚至可以靠猜,即使对于汇编小白来说。
逆向分析出的第一个循环结构
勉强分析出来一点逻辑,看起来能用,但是不知道是不是错的,正在想办法操作一下(迫真
duangsuse::Echo
勉强分析出来一点逻辑,看起来能用,但是不知道是不是错的,正在想办法操作一下(迫真
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
勉强分析出来一点逻辑,看起来能用,但是不知道是不是错的,正在想办法操作一下(迫真
一顿分析猛如虎,再看结果 Assertation failed(
duangsuse::Echo
liba.so
安排一下手机上测试能不能正常使用(
刚刚逆向分析实现的 liba.so!me
coolapk_a_kdev_1.zip
139.3 KB
更新
#reveng #tools #share 分享一些开源机器代码 REverse engineering 工具 ❤️

== https://github.com/namhyung/dwarview

ELF DWARF 调试符号信息查看器

== https://igio90.github.io/Dwarf/docs/installation.html

一个普通的(并非逆向工程用)调试器

== https://github.com/wisk/medusa

一个普通有 GUI 的 disassembler

== https://gitlab.com/p8n/panopticon

Rust 的跨机器代码指令平台反汇编工具

== https://github.com/cea-sec/miasm#user-content-assembling--disassembling

让 Radare2 可以使用 miasm Python 工具集工作

== https://github.com/pwndbg/pwndbg#readme

Pwndbg 是一个 GDB 插件,可以让 Source-level debugger GDB 一瞬变成 assembly level debugging 的好工具
妄图继续往调试符号里找东西(