duangsuse::Echo
酷安大佬们很聪明,我以为(对『破解者』来说)那么难看的 *char 操作都是酷大佬写的,可其实是 GCC 4.9 写的(跑
[DuangSUSE@duangsuse]~/Projects/HackingCoolApk/liba/RE/dwarview% base64 -d有点意思了 🤔
e7177eb11a13ea5672c543da1690e302dG9rZW46Ly9jb20uY29vbGFway5tYXJrZXQvYzY3ZWY1OTQzNzg0ZDA5NzUwZGNmYmIzMTAyMGYwYWI_7d3bcfe1ca700fdccf5a8595f98f70d8
{�{���խwy�z�g9�wZׯt{}6token://com.coolapk.market/c67ef5943784d09750dcfbb31020f0abbase64: 输入无效
duangsuse::Echo
[DuangSUSE@duangsuse]~/Projects/HackingCoolApk/liba/RE/dwarview% base64 -d e7177eb11a13ea5672c543da1690e302dG9rZW46Ly9jb20uY29vbGFway5tYXJrZXQvYzY3ZWY1OTQzNzg0ZDA5NzUwZGNmYmIzMTAyMGYwYWI_7d3bcfe1ca700fdccf5a8595f98f70d8 {�{���խwy�z�g9�wZׯt{}6token://com.c…
puts Base64.decode64(Base64.decode64('OGQwN2Y4OWY1OTU4YTVmY2NkZjAwN2FjMWVmY2IzZDcvSVdZd1lHTXlBVE16SW1ZbU5HWndVek41QURaMGd6TnpRVE8xWVdaM1l6WXZRWFpySlhZdDV5YXdGR2J2OTJZdTAyYmo5eUw2NFdacjlHZDIwM2UwOTYxYWQzNDVjMjc2NWFlMzFhMTFiZTc3MTdl').reverse)
duangsuse::Echo
有时候可能会很 SSA(Static Single Assignment) 地想,是不是找到了最后要的某个东西,就能根据它推断出它的依赖逻辑呢?这个本地变量就是最后的 Token 结果。
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
邪恶的 duangsuse 居然把这个依赖 DAG 收起来了... 🤔
你们这个是个什么口令生成算法啊,你们这是雷普前端开发者们啊你们这个算法。
麻烦你们,真的太过分了你们搞这个『加密算法』干什么,我的项目每一行代码都过不了那个 lint 检查啊,它现在没法连上你们的 API,你叫我项目怎么办啊,它还事个幼儿园基本的弱智应用好不好。
你们这是什么算法啊,哼!哼!啊啊啊啊啊啊啊。你们害死我项目了谁是出要写这种东西主意的快出来你们写代码的,再不出来我 ****** 了啊!
我跟你们说你们这群 Android 开发者啊,一天到晚搞什么这些加密啊代码保护啊会害死你们的(迫真)
你们没有前途我跟你们说你们这400多号人好好写 Jawa 不好么,一天到晚 show C/C++ 有什么意思,有什么意思啊,我偶尔写一下都快被恶心死了。
麻烦你们重视一下你们的 Jack 有点发展目标好不好,一天到晚写写 Rx 写写 Vertx 写写 Databinding 不是人啊,你们一天到晚搞 C++ 不好好写 pattern 没有前途的,NDK 害死人。
#Haha #security #Android #dev 😤
麻烦你们,真的太过分了你们搞这个『加密算法』干什么,我的项目每一行代码都过不了那个 lint 检查啊,它现在没法连上你们的 API,你叫我项目怎么办啊,它还事个幼儿园基本的弱智应用好不好。
你们这是什么算法啊,哼!哼!啊啊啊啊啊啊啊。你们害死我项目了谁是出要写这种东西主意的快出来你们写代码的,再不出来我 ****** 了啊!
我跟你们说你们这群 Android 开发者啊,一天到晚搞什么这些加密啊代码保护啊会害死你们的(迫真)
你们没有前途我跟你们说你们这400多号人好好写 Jawa 不好么,一天到晚 show C/C++ 有什么意思,有什么意思啊,我偶尔写一下都快被恶心死了。
麻烦你们重视一下你们的 Jack 有点发展目标好不好,一天到晚写写 Rx 写写 Vertx 写写 Databinding 不是人啊,你们一天到晚搞 C++ 不好好写 pattern 没有前途的,NDK 害死人。
#Haha #security #Android #dev 😤
2a6e2adc2897c8d8133db17c2cd3b1045834ce58-d7d5-38eb-95d5-563167a1983d0x588f16cd
(第一部分是机器代码计算的校验和(用到了 base64 和 MD5),我花了两天用 C 重写了,第二部分是 UUID,第三部分是当前 UNIX 时间的十六进制表示)
7fa737c3bc4e80f1381d3c7e1bfdd40d47b11e0b-97b6-454b-9831-ccaff8f19f020x5c6a5245
🤔 哦... 我记得看汇编的时候的确可能拼接了这个
还是不行,
(第一部分是机器代码计算的校验和(用到了 base64 和 MD5),我花了两天用 C 重写了,第二部分是 UUID,第三部分是当前 UNIX 时间的十六进制表示)
7fa737c3bc4e80f1381d3c7e1bfdd40d47b11e0b-97b6-454b-9831-ccaff8f19f020x5c6a5245
🤔 哦... 我记得看汇编的时候的确可能拼接了这个
0x, 不过因为不是用 strcat 所以我没加,加上试试还是不行,
duangsuse::Echo
2a6e2adc2897c8d8133db17c2cd3b1045834ce58-d7d5-38eb-95d5-563167a1983d0x588f16cd (第一部分是机器代码计算的校验和(用到了 base64 和 MD5),我花了两天用 C 重写了,第二部分是 UUID,第三部分是当前 UNIX 时间的十六进制表示) 7fa737c3bc4e80f1381d3c7e1bfdd40d47b11e0b-97b6-454b-9831-ccaff8f19f020x5c6a5245 🤔 哦... 我记得看汇编的时候的确可能拼接了这个…
我用 UUIDParser 弄了一下,发现给的 UUID 其实都有区别(一个是 name based 一个是 time based)... 最讨厌的就是有时候动态分析很麻烦 🤔
我看这逻辑也挺 plain 的,继续分析,Ruby 重写一下 emmmm...
bd 就是 base64 decode(dst, src)
be 就是 base64 encode(dst, src, srclen)
me 就是 MD5 based message digest(dst, src)
r 就是 reverse string(s)
🤔 好像虽然不是很能完全理解,但是基于调试符号的帮助,重写也不是很困难,我得想想这些名字都会代表什么
我看这逻辑也挺 plain 的,继续分析,Ruby 重写一下 emmmm...
bd 就是 base64 decode(dst, src)
be 就是 base64 encode(dst, src, srclen)
me 就是 MD5 based message digest(dst, src)
r 就是 reverse string(s)
🤔 好像虽然不是很能完全理解,但是基于调试符号的帮助,重写也不是很困难,我得想想这些名字都会代表什么
== /Users/kjsolo/StudioProjects/
== CoolLibrary/app/src/main/jni/a.c
尝试尽可能还原代码原貌,利用从 DWARF 调试符号里以及反汇编分析获得的信息。
不过很好玩的样子(迫真)
我居然彻底还原了原项目的代码风格布局... 细思恐极
== CoolLibrary/app/src/main/jni/a.c
尝试尽可能还原代码原貌,利用从 DWARF 调试符号里以及反汇编分析获得的信息。
void r(char *s) // L13
{ // L14
int length = strlen(s); // L15
int c, i, j; // L16
for (i = 0, j = length - 1; i < j; i++) // L18
{
c = s[i]; // L20
s[i] = s[j]; // L21
s[j] = c; // L22
j--;
} // L24
}
void bd(char *dst, const char *src) // L27
{
BD(dst, src);
}
void me(char *dst, const char *src) // L33
{
unsigned char *digest[16]; // L35
MD5_CTX context; // L36
MI(&context);
MU(&context, src, strlen(src));
MF(digest, &context);
for (int i = 0; i <= 15; i++) {
sprintf(dst[i + i], "%02x", digest[i]);
}
}
void be(char *dst, const char *src) // L47
{
int src_len = strlen(src);
BE(dst, src, src_len);
}
虽然看起来没用(其实也没多大用,大嘘)不过很好玩的样子(迫真)
我居然彻底还原了原项目的代码风格布局... 细思恐极
duangsuse::Echo
== /Users/kjsolo/StudioProjects/ == CoolLibrary/app/src/main/jni/a.c 尝试尽可能还原代码原貌,利用从 DWARF 调试符号里以及反汇编分析获得的信息。 void r(char *s) // L13 { // L14 int length = strlen(s); // L15 int c, i, j; // L16 for (i = 0, j = length - 1; i < j; i++) // L18…
This media is not supported in your browser
VIEW IN TELEGRAM
duangsuse::Echo
🤔 Sticker
我们来对照一下这些代码和他们的汇编形式,让我们自己也来当一回 GCC 4.9: 🤔🐔❓为什么要手动『编译』一些源代码呢? #Compiler #CS #PL #backend #reveng
为什么要手动分析一些反汇编代码呢?
人不是生来就是 native 编译器,所以我们要写汇编,要了解各种实体机,X86、ARM、MIPS、AVR,看各种反汇编让自己能成为编译器(虽然依然不支持向量化和某些高等编译优化诸如逃逸分析指针别名还有更高级的寄存器分配算法,哭哭)。
有时候或许做梦能梦到自己变成编译器,正在拿着一张 native 代码的草稿图纸后序遍历游走在 AST(Abstract Syntax Tree)的大森林之中... 🤔
或许我今天的任务是为一个叫 CoolLibrary 的项目以 linux-android 的格式生成 i686 机器代码
我的前端们,预处理器、分词器、解析器,他们处理项目结构,他们处理符号定义替换、展开宏、保证了各个编译单元的独立解耦... 然后他们把我需要的东西 — AST 喂给我,而我则会处理 AST,告诉他们翻译生成的程序或者哪里有错误
我走过各种个样的子树 — 有字面量、常量、变量、指针、数组、控制结构、代码块、子程序定义、子程序调用,他们有各种各样自己的属性、flag,有时候我从背包里找出图纸判断他们是否真的应该在这,有时候我会确认他们的属性是否设置得当,有时候我拿出笔记本,记录下他们的存在以便以后查看
K&R C、C89(ANSI C)、C99、C11... 这些冗长生硬的定义通通不是我的实际写照,我只是一个简单的小工具,我负责把你们的一行行容易理解的行为代码用另外一种更低级、更底层,能让实际机器开心的方式表述出来
我所认识并理解的是一门古老的『编程语言』,它的名字叫 C,源自 BCPL,而 BCPL 又源自 CPL,BCPL 已经是 20 世纪 60 年代的东西了,即使这样也没有被 2018 年的你们抛弃?
有时候我会发现森林中暗含的危险路径,打破了抽象类型系统的限制,我就会回溯停止代码生成工作,忠实地汇报错误。
有时候我能走完这个森林,并且完成有时候会一起进行优化和低级化代码的任务,生成那些被你们认为是黑盒的东西,你们认为它牢不可破,可是我知道,即便是使用我的同道 packer / obfuscator 再对我生成的程序进行处理,也永远有人能看透我翻译出的机械逻辑背后藏着的东西,因为我... 我只是个工具
如果你不知道我对你的代码做了些什么,又怎么能看到我留下的『可执行』数据背后的秘密?
如果我是编译器,管它是 JIT 即时编译器还是 AOT 编译器,这真是最吼的。 🤔🐸(尬膜)
一言不合就念诗(划掉)
== 第一个例子,简单到只包含调用的函数
void bd(char *dst, const char *src)== 第二个例子,普通一点的包含本地变量的函数
{
BD(dst, src);
}
void be(char *dst, const char *src)== 第三个例子,一个字符串倒序程序,它包含本地变量和一个循环控制结构
{
size_t src_len = strlen(src);
BE(dst, src, src_len);
}
void r(char *s) {
int length = strlen(s);
int c, i, j;
for (i = 0, j = length -1; i < j; i++)
{
c = s[i];
s[i] = s[j];
s[j] = s[i];
j--;
}
}
== 最后一个例子,逻辑稍微长一点的程序,同上void me(char *dst, const char *src)
{
unsigned char *digest;
MD5_CTX context;
MI(&context);
MU(&context, src, strlen(src));
MF(digest, &context);
for (int i = 0; i <= 15; i++)
sprintf(dst[i * 2], "%02x", digest[i]);
}