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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
说起来最近提到『节约内存』『降低回收开销』的频率越来越高了,莫非是因为被 #Lua 的胸襟震惊而开始强迫症了吗…… #Java #Kotlin
oop1.lua
1.2 KB
#Lua #oop #PL 🤔刚才体验写标准Android之前又把 LuaOOP 默写了一遍,构造器调用子类优先了,重写后果然感觉优化了不少(也提升了效率编程自信心)
#recommended #blog #security #game #web #php #lua #js #net #windows 这个人涉猎非常广,WinApi、网络、逆向、密码学 都有实践经历,而且非常有活力,之前忘记加紧关注了(当然我觉得代码质量还能更好点)
#China #tech 🌚 脸红不? 2021 还不会写 ANSI C 编译器的同学们(
https://blog.csdn.net/myan/article/details/490 《Lua让我脸红》
Python是荷兰人写的,Ruby是日本人写的, #Lua 是巴西人写的,我这个中国人只能在这里脸红。

“ 我1996年就学会了C,1997年就跑去研究Win32 API,后来是C++,STL,Java... 直到2002年看到C Interfaces and Implementations,才知道仅仅用ANSI C就可以实现一个强大的优美的library,直到2004年看到Lua的源代码才知道仅仅用ANSI C就可以实现一个非常快的虚拟机、非常棒的解释器/编译器和非常漂亮的语言实现。

但是,看完这条的第一个链接你就会了 🌝(跑,但这篇文章的确精炼而且 practical
#js #DontKnow 原型链:(感谢 @JackWorks 提供相关信息)

访问语法都是动态解析的,比如 x.prop
x["prop"]
就是
x.[[Get]]("prop", x)

ES 里一共有五种不同的 [[Get]] 实现,分别是
- 普通对象 [规范]
- Argument 对象(你们今天应该不会用到了)
- 类数组对象(数组的特殊行为就在这里)
- 模块对象(import * as Mod 里的 Mod
- Proxy 对象(reflect proxy 全 delegate)

此外, Object.getOwnPropertyDescriptor(o, k) 可以获取可配置 enumerable, writeable 等属性的配置对象
Object.[get/set]PrototypeOf(o)
o.__proto__ 是它的「超类虚表」

[[Get]] 过程的 Receiver (第二参数)很重要,如果没有这个 Receiver,基于原型链的 OOP 其实是做不起来的

原来是往 proto 上找属性!
这就解释了 Array.prototype.map 之类的东西

parent = { method() { return this; } }
child = {}; child.__proto__ = parent;
child.a = 1; child.method(); // 返回自身
最简单的解释是, Receiver 就是属性访问的时候最上层的那个对象,会被当成 this 用。
因为在这个算法里你可以看到,Receiver 是跟着递归一路传递下去的

原来是 o["RESOLVE"](o.prototype, "attr", receiver=o) !(当然,肯定是先查本地,然后才查 prototype
本地如果有就不会查 prototype 了

明白了,和之前写的 LuaOOP 很像,都是层叠属性查找

“ 大佬能交换下原型链相关知识吗
之前看加 Mixin 好像是说把 prototype 除了哪两个属性的什么全部复制一下
#Python#Ruby 的情况我都了解, Py 是 mro() 链查询, A.wtfa.wtf 都是往 class A 找成员,后者实质是 type(a).wtf(a) 所以得到 bound method ,而直接 A.wtf 就是 bind 操作
@staticmethod 直接不收 self ,不需要 bound 所以可以在类和实例上用

https://paste.ubuntu.com/p/tJv7QpSjGt/ liuil-util 的 #TypeScript mixin.ts 重写
duangsuse::Echo
https://t.me/vvb2060Channel/416 #Android #Security #aop asm inline hook 当然是任意点都可以,实际上 frida 配 xposed 开发是真好吧🤔 /proc/self 都可以 mount --bind ,但是改动是系统级的。 通常做法就是由框架来实现访问权共享,像 Riru 一样换一个 preload .so 来实现 hook 我觉得应用层开发者尝试对抗系统动态分析是很愚蠢的行为,毕竟你又不是搞安全的,凭 Proguard 组搞出来…
为了避免被认为是在指点江山我就简单 PoC 一下,真的不需要十行代码。 毕竟这个「反破解手段」门槛也太低了,只需改动 .h 文件&重编译,其它都自动兼容了。
而加密 bytecode 的各种方法全都逃不过内存 dump ,因为「原原本本」的程序文件是虚拟机要求的,总是要还原。 hook 一下虚拟机的 load() 即 luaZ_undump() 就都出来了,代码保护唯一有效的是削除命名标识符的本义,或者对程序做些预处理和切分什么的(对这些,基于符号执行的 smalivm 类反混工具也能消除),但是大部分有「产权保护」意识的人 意识不到吧😒

目标只是得出两版 #Lua 指令号直接的对应关系,也就是只需做指令id 数组的读取,得出的对应关系用于 patch 给 chunkspy 等工具。

本来说是可以用 getOpcode(buf, i) 的,忘记数组迭代需要长度的问题了,就用迭代器吧…… 也是惰性计算的😒

首先自编个 lua luac (实质都是 liblua 的命令行工具
curl -O http://www.lua.org/ftp/lua-5.4.2.tar.gz
tar xf lua-* &&cd lua-*/src/
make luac lua

#sysadmin 科普下 lua.org 的 doc 里 curl/tar 的 -R/-z 是 设置文件mtime/gz解压

看看 https://bbs.pediy.com/thread-250618.htm
https://t.me/berd_channel/1647
可以参考

Luac chunk 文件是比较标准带 insn size 的二进制结构, size_t 一般为 4 (int32) 大端字节序,因为只需要读取 opcode 我就做个比较 hack 的操作——hexdump diff 断言指令数组头的偏移量,本来想可以直接取每条指令首字节,没想到这个好像是仅 7 bit ,那就只能 import struct😓
然后指令集也不必写完整的,反正也没有 unluac ,源码手改的,自己验证意思意思够了。

lopnames.h 对虚拟机无意义, lopcodes.c 只是定义指令格式的,所以要改 .h 里的顺序,稍后 grep -r 'ORDER OP' 还会发现必须同时更改 .c 的顺序,而且还得修正 lua.h 的一处 #define 🌚 (不过和 lcode.h 的 OPR_x 以及 ltm.h 没关系,因为 opr 是以 OP_ADD+i 及 TM_ADD+i 的方式两向对应的 )
其实如果不改 ltm.h 而想保证元表事件正常派发,那 OP_ADD 到 OP_NOT 直接的顺序都不能变🌝
不过这里就随便点,反正没用到~

用于乱序的 py 脚本:
同时 shuf .c array 和 .h enum 的索引号,总之就是先搞出 index mapping 再 apply 它两次。 🌚

用于对应的脚本(见下下条):
d[op[i]] = names[op_orig[i]]

胡话:呃,好像是 d[k] = d1[d[k]] ... 不对
其实变的是 k 吧(re-associateBy), d[k1] = d[k] 其中 k1=d1.keyOf(k) ,因为 v 都是复制过来的。

#plt #ce #backend 反破解小指南 🦜
嘛,其实这个还是有强化的方法的。 只需这个有强烈愿望🧐并且敢动 C 虚拟机🌝实现代码的人 对他的每个单个应用 重编译乱 opcode 的私有版 lua
同时更改下 LuaVM 指令格式 bitmask 里操作数的顺序,并且以自有算法加密常量池(必须由虚拟机层来解密,最好是惰性完成的 内部传输性 loadk 只传常量编号不解密),这样对 naive 的破解者就非常棘手了,只能从外部 API 分析某一特性点的实现方法惹🌚

自有版虚拟机的代码文件看起来符合规范(因为你改得少),但是完全无法被通常工具读取,一些虚拟机壳也是出于同样的意图(which 我没在 Android 上见到过,设计这种加壳器需要一定编译原理或状态机的知识 需要预处理 bytecode)

最关键的一点就是孤立自己利用到的技术,让破解者无法使用针对性工具,然后增加破解者自写工具的难度,尽可能用没工具的 native 平台叠加难度。单机程序用惩罚机制来反动态分析?可笑。程序状态是不可信的,稍有常识的坏人完全可以保留某 fork 的整机状态,你检查虚拟机都不行,有的是机会给检测方法 hook 光光;用别人的反破库,也容易被找到针对性反反破工具。😒
其实嘛,越是简单的代码越接近真理,越往程序的根基走,手段越能令破解者头疼。

其实用私有版 luaVM 不暴露指令号对应关系就已经很安全了(当然坏人🌝还是可以用生成 code 看 vm state 的方法甄别指令,虚拟机状态就不是纯二进制领域的人能魔改的了🤪),但最好还是用预处理给 luaV_execute 的 opcode switch 每个 case 加点随机乱代码,防止被源码相似性搜索(这个只需要反汇编字符串匹配 破解者就能完成)。

介于 C 的静态自动分析尚无完整解法,对每个模块都要还原虚拟机指令才能反编译出真实逻辑,就可以说是「无法破解」的软件了🤣
你掌控程序流程,你掌控无物;你掌控程序码解释,你掌控一切。
越是在根基做限制越难破解,但是外部 API 和 memdump 依然没办法对抗,但至少,这样反调试代码就不易被分析了🌚 这些代码能造成巨大的麻烦,让破解者不知从何下手,例如反外部 API 断点和管理加密的常量池,制造 garbage String 来混淆 memdump 。

什么叫做欺骗系统,「系统」这个概念都是针对软件运行时而言的,运行时可以是带trace/hook的实机、虚拟机或者静态分析器,这些都是合法合理的运行时,因为,程序只是数据而已。「我的代码,我的权利、我的私产」?谁能想到那么多啊😅
除非有一天 DRM 会无法被模拟复制破解,不然最实际的方法是把软件做得足够大,然后诉诸法律或己方威权。
duangsuse::Echo
为了避免被认为是在指点江山我就简单 PoC 一下,真的不需要十行代码。 毕竟这个「反破解手段」门槛也太低了,只需改动 .h 文件&重编译,其它都自动兼容了。 而加密 bytecode 的各种方法全都逃不过内存 dump ,因为「原原本本」的程序文件是虚拟机要求的,总是要还原。 hook 一下虚拟机的 load() 即 luaZ_undump() 就都出来了,代码保护唯一有效的是削除命名标识符的本义,或者对程序做些预处理和切分什么的(对这些,基于符号执行的 smalivm 类反混工具也能消除),但是大部分有「产权保护」意识的人…
刚才写了一大篇都是理论,也是因为我低估了问题的麻烦度在手机上写了大半天…… 🙊 确实测试还是需要的。

嘛,除了 luac wtf.lua 其实也可以这样拿到字节码去对照(毕竟 liblua 是带 luaC_ luaU_ 编译器的,刚刚也说了 lua luac 只是 CLI 前端, liblua 才是本体)
也是我一开始就没从要逆向谁的应用的角度来想🌝,没去研究不用 luac 怎么得字节码。 可方便了
过会我也不会提供魔改反编译器或者 .luac 文件的辅助程序什么的,正确的做法是魔改 unluac 扩展支持加载 json 配置
https://www.lua.org/manual/5.4/manual.html#pdf-file:read #Lua 的 io file 用的 lines() read("n") "a" "l" fmtstr ,真的很难猜中啊 🌚 table.concat({1,2,3}, "") 对 iter 不起效;不过我突然发现 dump() 其实要 function... 要靠 eval 类接口了

function codeobj()
-- 用到几乎所有 opcode 的程序体
end
io.open("code.luac", "wb"):write(string.dump(codeobj))


文章里也写了 hexdump diff 本来就可以拿 iter if == 替换 😅思维定势 不过也是因为我面向 array binstruct 了
这里只是 PoC ,没有 LuaS 头的兼容性和 size 定义的问题,那个 Berd 写过
https://github.com/fengberd/xLuaDumper/blob/master/xLuaDumper/opcode.lua
loadkx, extraarg, testset 应该是优化指令🤔 反正这里不必是全集,闭包 upvalue 的没问题就行。

io.open("o.luac","wb"):write(string.dump(loadfile("a.lua")))
可以用 https://github.com/viruscamp/luadec/blob/master/ChunkSpy/ChunkSpy53.lua 看看,报错就改它的 config 。好了是这样。

对应表:
import struct
def mask1(n): return sum([1<<i for i in range(n)])
def readOpcodes(f, nbit=7, fmt="<I"): # LE unsigned int
mask = mask1(nbit)
n = f.read()
for _ in range(n): yield f.read(struct.calcsize(fmt))&mask
from sys import argv
def main(args=argv[1:]):
def opcodes(fp): f=open(fp, "rb"); f.seek(46); return readOpcodes(f)
(f, fOrig) = map(insnFile, args)
print({op1:op for op1,op in zip(f, fOrig)})


当然如果有 opnames 可以 re-associateBy 也即 op1: names[op]names.associateBy { d.keyOf(it.key) } ,不过我觉得那不重要。
#code https://gist.github.com/duangsuse/90366621af2d206867496f7eb1e42438 写这里 🌝 竟然花了这么久
那个用来自动重排 opcodes 的脚本实在是太难看了,虽然我努力在写简单…… 毕竟是在处理 C 源代码 🤪
真的没问题吗

#Android #net 还看到了这个 https://t.me/dsuses/4769
> https://t.me/dsuse/1064
https://bellard.org/otcc/otccn.c 是tccboot所用JIT编译的最简版

呃.. 第一次见到 wiki 编辑战
小时候(高中) 很喜欢 #mozilla #Rust ,还写了这个(列表处理)程序

大概就是暗暗觉得……高性能又开源(根正描红的那种,练习时长两年半只为开源语言,太感人了)

后来看的就淡了,因为rust真的很(烧脑?)

我觉得能和 C FFI 的某种意义上都是系统,比如 py 的嵌入式GPIO libs
.Net 有P/Invoke和struct{}, 栈分配 啊,他们可能觉得入选 osdev.wiki 才叫系统编程

无非就是FFI和struct指针的问题,既然 py (cffi能读写指针), .Net unsafe marshall 支持二进制,也是能实现OSkrnl的需求

但KN 不是,因为强类型强检查 弱框架,写着麻烦

系统级就是你可以用来写内核和驱动
这个 lunatik 能在内核层开启 #Lua REPL
这个 https://duskos.org/#operator 类似 tccboot, 但是嵌入式的
2