duangsuse::Echo
Template.java.dia
总而言之,用 PDL(Program Design Language) 可以表示为:
#C
#Cplusplus
#PHP
#Ruby
#Lua
#VisualBasic (VB.NET)
#CSharp
fun main(argv)那么我就顺手再写个 C 的版本和 C++ 的版本和 PHP 的版本和 Ruby 的版本和 VisualBasic 的版本和 CSharp 的版本... 反正我还有很多事没做... 啊 😵
String? template = readFormatString();
String? formated = String.format(template.getOr { exit(EXIT_FAILURE); }, argv);
formated.let(stdout::println);
fun readFormatString()
File.Path fileName = getenv("TEMPLATE") ?: "template";
File templateFile = File(fileName);
unless file.exists and file.isFile: raise "File ${fileName} not found"
unless file.canRead: raise "File ${fileName}: cannot read"
FileInputStream is = null;
byte templateBytes;
begin /* readAll is into templateBytes */
templateBytes = new byte[is.available];
is = FileInputStream(templateFile);
is.read(templateBytes);
handle IOException rethrow
ensure is.close
return String(templateBytes);
#C
#Cplusplus
#PHP
#Ruby
#Lua
#VisualBasic (VB.NET)
#CSharp
#Kotlin #Java #Lua #design #cs
Delegate 呢,和
这就是咱漂亮的 Kotlin 对 Delegate 的支持(
负责的老师会告诉面向对象的程序是一群对象相互「发消息(message passing)」的过程,确实是这样;而且 OOP 的
Delegate 在你了解这个事实的时候很直白:它就是把某些方法(调用的"消息")从某个 receiver 上转移给另一个 receiver ,所以我们可以更灵活的利用面向对象的继承,甚至实现"多继承"…… 在上例里,
如果你利用 Delegate, 则可以完美解决上面用 Mixin 很麻烦的复用问题,定义一个需实现的接口(子集)即可 (而且
附赠另两个特色设计模式: Visitor 和 Reducer(非标准) #PLT #ce #OOP
经常写基于 Iterable<T> (map/fliter/sorted/zip/first/...) 的程序吗?那你应该听说过
Reducer 和 Fold 是另一个版本的 forEach: 假设你是要拿到序列的最大值/最小值(min/max),或者把它化为映射表(associate/groupBy),或者仅仅只是复制一份 List ,但不想写重复代码,你会怎么做?
以上操作或依赖一个可变量, 或是 MutableList 什么的。 他们的交集是,都依赖一个(变)量,且在
我写了泛用的
ParserKt 利用了这个设计模式,从而实现
流式编程是来自于函数式 #FP 的智慧,这可以视作它们广为人知的特色(自Lisp就有,地位类似OOP链式调用,不过有了 Kotlin 的 scope function (let/run/apply/also) 后我觉得 Builder 等设计模式要无地自容了😂,流式编程和 MapReduce 却越来越火,超过 LINQ 和 SQL ,嘿嘿),看看你听没听说过这些处理方法: flatMap(trans)/zipWithNext()/first(n)/takeWhile(predicate)/foldRight 。大体上分为 映射(map)/过滤(filterNotNull,first,takeWhile)/排序(sorted,reversed,shuffle)/组合(zip,zipWithNext,interleave)/归纳(fold/associate/flatten/maxBy) 五大类。
注: interleave/shuffle/flatten 应该是不太常见的用法, that's correct ,简单来说就是 交替流/乱序洗牌/铺平嵌套流
顺便一提:猜猜这个是什么:
但是
Delegate 呢,和
java.lang.reflect.Proxy (方法调用拦截) 当然是有区别的啊,不过提到 reflect.Proxy 可能有助于对 Delegate 的形象理解。class MyDict(private val m: MutableMap<K, V> = mutableMapOf()): Map<K, V> by m 这就是咱漂亮的 Kotlin 对 Delegate 的支持(
T by m) 里 T 是任意接口,它会代理其中的成员(从 this)到 m 这个 receiver 上。负责的老师会告诉面向对象的程序是一群对象相互「发消息(message passing)」的过程,确实是这样;而且 OOP 的
this(即receiver引用, 或者说"主语") 使得我们以更自然的方法编程和划分代码块,不过发消息的确切说法是「驱使」或「属性访问」 (就是引用某个「主语」上的动词或名词)。Delegate 在你了解这个事实的时候很直白:它就是把某些方法(调用的"消息")从某个 receiver 上转移给另一个 receiver ,所以我们可以更灵活的利用面向对象的继承,甚至实现"多继承"…… 在上例里,
MutableMap 是个无构造器的类,但我们利用 Delegate 使它上的方法(get,set,remove,...) 通通可以访问了 (当然这个"子类型"并不兼容 mutableMapOf() 的实际类型,它是另一个继承自 Any 的新类型,但如果有 m 实现了的 interface 则其方法皆可被代理,这才是"代理"存在的意义)如果你利用 Delegate, 则可以完美解决上面用 Mixin 很麻烦的复用问题,定义一个需实现的接口(子集)即可 (而且
AnimalBoilerplate 也可以使用 this 外的变量, 同时不局限于访问某 interface 了)。 附赠另两个特色设计模式: Visitor 和 Reducer(非标准) #PLT #ce #OOP
经常写基于 Iterable<T> (map/fliter/sorted/zip/first/...) 的程序吗?那你应该听说过
java.util.stream.Collector :import java.util.stream.*我最讨厌 Java 的一点就是它废话太多了,聒噪。仔细看 Collector 里有什么?
Stream.of(1, 2).map { it + 1 }.collect(Collectors.asList())
supplier; accumulator:BiConsumer; combiner:BinOperator; finisher ,这就是所谓的 "architect" 到处弄 XXX er/or 的对象,不懂得沉默是金、混淆组合(combine)流与普通映射/过滤流、没有复用 Collection 而是用了所谓的 finisher,咱才懒得看它呢。Reducer 和 Fold 是另一个版本的 forEach: 假设你是要拿到序列的最大值/最小值(min/max),或者把它化为映射表(associate/groupBy),或者仅仅只是复制一份 List ,但不想写重复代码,你会怎么做?
val xs = listOf(1, 2, 3)等价这个"折叠"循环:
xs.reduce { a, b -> kotlin.math.max(a, b) } // 3
var acc=xs[0]; xs.indices.drop(1).forEach { acc = kotlin.math.max(acc, it) }; acc
当然如果是求和的话,也可以不要求列表至少存1项: xs.fold(0) { a, b -> a+b }
fold 操作往往比 reduce 更实用(如 xs.fold(StringBuilder(), op) ),如果我们把他们结合起来变成对象呢?就成了 Fold/Reducer 。这名词是我自造的 😗以上操作或依赖一个可变量, 或是 MutableList 什么的。 他们的交集是,都依赖一个(变)量,且在
<T> 流结束的时候,返回结果类型 <R> ,所以必须建模为对象,因为它要构造并持有一个状态并且在 accept(T) 时更新此状态。我写了泛用的
ConvertReducer<T,R> 和 ModifyReducer<T,A> 两个基类,因为这不是标准设计模式我不赘述,有兴趣找我的代码看,Fold 是 () -> Reducer (R.的构造器类型)。ParserKt 利用了这个设计模式,从而实现
Repeat(asList()/*asInt(radix=10), asMap,joinAsString...*/, digit) 这种方便的定义式单项构造。流式编程是来自于函数式 #FP 的智慧,这可以视作它们广为人知的特色(自Lisp就有,地位类似OOP链式调用,不过有了 Kotlin 的 scope function (let/run/apply/also) 后我觉得 Builder 等设计模式要无地自容了😂,流式编程和 MapReduce 却越来越火,超过 LINQ 和 SQL ,嘿嘿),看看你听没听说过这些处理方法: flatMap(trans)/zipWithNext()/first(n)/takeWhile(predicate)/foldRight 。大体上分为 映射(map)/过滤(filterNotNull,first,takeWhile)/排序(sorted,reversed,shuffle)/组合(zip,zipWithNext,interleave)/归纳(fold/associate/flatten/maxBy) 五大类。
注: interleave/shuffle/flatten 应该是不太常见的用法, that's correct ,简单来说就是 交替流/乱序洗牌/铺平嵌套流
顺便一提:猜猜这个是什么:
def zipPairs(xs): return zip(xs[0::2], xs[1::2])。当然这么简单定义不了 zipWithNext, 它和 fold (的累积变量)系出同门... 😂但是
zipWithNext = lambda xs: zip(xs, xs[1:]) 我们仍没有用到重赋值,这证明了函数式的组合表现力,的确应该更新观念了。" and ".join([f"{a} < {b}" for (a,b) in zipWithNext("1 2 3".split(" "))]) #'1 < 2 and 2 < 3'
很有趣不是吗? 定义式的代码,根本无需数学化的简写语法(点名批评 Py 的 slice)来保持他它们的易读性,这也是 Kotlin 的一大特色。
duangsuse::Echo
#learn #PL #CS 首先引出问题,什么是操作符链(中缀链) 1+2*3; 1*2+3 ,它们可以被简单理解为以 +-*/ 运算符(操作符)分割的单项 但其实不然,用形式化文法(以『左递归』)应当是这样: Atom = [0-9]* | "("Expr")" | "-"Expr Expr1 = Atom "*"/"/" Atom Expr = Expr1 "+"/"-" Expr1 上面,我们定义了『表达式』和『基元(Atom)』两项,我们以 Expr, Expr1 区分了加减法、乘除法的优先级 …
🤔 理解了 #Lua 的做法后,我对「精雕细琢」这个词也有了新的领悟。 一个看起来完全不相关的算法,竟然可以拿来优化,真是妙不可言……
#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
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就可以实现一个非常快的虚拟机、非常棒的解释器/编译器和非常漂亮的语言实现。
但是,看完这条的第一个链接你就
#js #DontKnow 原型链:(感谢 @JackWorks 提供相关信息)
访问语法都是动态解析的,比如
- 普通对象 [规范]
-
- 类数组对象(数组的特殊行为就在这里)
- 模块对象(
-
此外,
原来是往 proto 上找属性!
这就解释了
因为在这个算法里你可以看到,Receiver 是跟着递归一路传递下去的
原来是
本地如果有就不会查 prototype 了
明白了,和之前写的 LuaOOP 很像,都是层叠属性查找
“ 大佬能交换下原型链相关知识吗
之前看加 Mixin 好像是说把 prototype 除了哪两个属性的什么全部复制一下
#Python 和 #Ruby 的情况我都了解, Py 是 mro() 链查询,
https://paste.ubuntu.com/p/tJv7QpSjGt/ liuil-util 的 #TypeScript mixin.ts 重写
访问语法都是动态解析的,比如
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.wtf 和 a.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 重写
Telegram
duangsuse::Echo
#Lua #oop #PL 🤔刚才体验写标准Android之前又把 LuaOOP 默写了一遍,构造器调用子类优先了,重写后果然感觉优化了不少(也提升了效率编程自信心)
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 的命令行工具
看看 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 ,那就只能
然后指令集也不必写完整的,反正也没有 unluac ,源码手改的,自己验证意思意思够了。
lopnames.h 对虚拟机无意义, lopcodes.c 只是定义指令格式的,所以要改 .h 里的顺序,稍后 grep -r 'ORDER OP' 还会发现必须同时更改 .c 的顺序,而且还得修正 lua.h 的一处
其实如果不改 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 会无法被模拟复制破解,不然最实际的方法是把软件做得足够大,然后诉诸法律或己方威权。
而加密 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 会无法被模拟复制破解,不然最实际的方法是把软件做得足够大,然后诉诸法律或己方威权。
Pediy
[原创]用 Lua 简单还原 OpCode 顺序-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
duangsuse::Echo
为了避免被认为是在指点江山我就简单 PoC 一下,真的不需要十行代码。 毕竟这个「反破解手段」门槛也太低了,只需改动 .h 文件&重编译,其它都自动兼容了。 而加密 bytecode 的各种方法全都逃不过内存 dump ,因为「原原本本」的程序文件是虚拟机要求的,总是要还原。 hook 一下虚拟机的 load() 即 luaZ_undump() 就都出来了,代码保护唯一有效的是削除命名标识符的本义,或者对程序做些预处理和切分什么的(对这些,基于符号执行的 smalivm 类反混工具也能消除),但是大部分有「产权保护」意识的人…
刚才写了一大篇都是理论,也是因为我低估了问题的麻烦度在手机上写了大半天…… 🙊 确实测试还是需要的。
嘛,除了
也是我一开始就没从要逆向谁的应用的角度来想🌝,没去研究不用 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 ,真的很难猜中啊 🌚
文章里也写了 hexdump diff 本来就可以拿 iter if == 替换 😅思维定势 不过也是因为我面向 array binstruct 了
这里只是 PoC ,没有 LuaS 头的兼容性和 size 定义的问题,那个 Berd 写过
https://github.com/fengberd/xLuaDumper/blob/master/xLuaDumper/opcode.lua
loadkx, extraarg, testset 应该是优化指令🤔 反正这里不必是全集,闭包 upvalue 的没问题就行。
对应表:
当然如果有 opnames 可以 re-associateBy 也即
#code https://gist.github.com/duangsuse/90366621af2d206867496f7eb1e42438 写这里 🌝 竟然花了这么久
那个用来自动重排 opcodes 的脚本实在是太难看了,虽然我努力在写简单…… 毕竟是在处理 C 源代码 🤪
真的没问题吗
#Android #net 还看到了这个 https://t.me/dsuses/4769
嘛,除了
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
GitHub
fengberd/xLuaDumper
Load xlua.dll and corresponding lua5X.dll to dump luac for a script - fengberd/xLuaDumper
duangsuse::Echo
刚才写了一大篇都是理论,也是因为我低估了问题的麻烦度在手机上写了大半天…… 🙊 确实测试还是需要的。 嘛,除了 luac wtf.lua 其实也可以这样拿到字节码去对照(毕竟 liblua 是带 luaC_ luaU_ 编译器的,刚刚也说了 lua luac 只是 CLI 前端, liblua 才是本体) 也是我一开始就没从要逆向谁的应用的角度来想🌝,没去研究不用 luac 怎么得字节码。 可方便了 过会我也不会提供魔改反编译器或者 .luac 文件的辅助程序什么的,正确的做法是魔改 unluac 扩展支持加载…
https://gist.github.com/duangsuse/90366621af2d206867496f7eb1e42438#file-shuf_opcode-py
好耶,我又重写了能自动生成 Lua 指令集重排的 py 脚本,这次 0 ambiguous 达成 😋
话说 #Lua 支持 load/do file/string 和 require/loadlib/load ,这么多字节码/eval类 API 呢
好耶,我又重写了能自动生成 Lua 指令集重排的 py 脚本,这次 0 ambiguous 达成 😋
话说 #Lua 支持 load/do file/string 和 require/loadlib/load ,这么多字节码/eval类 API 呢
Gist
Lua Opcode reordering and its analysics
Lua Opcode reordering and its analysics. GitHub Gist: instantly share code, notes, and snippets.
Forwarded from 依云的技术资源分享
> 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, 但是嵌入式的
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, 但是嵌入式的
Telegram
duangsuse::Echo
TCC还有一个编译Linux到内存然后直接跑起来的buff( 还没有编译过Linux内核的咸鱼们可以来体验一下廉价的内核编译 ~~虽然是全自动的~~.
只需一TCCBOOT, 一64MiB内存 x86机, 大约1s的二十倍时间即可体验.
TCC is distributed under the GNU Lesser General Public License.
tar -xf qemu_tccboot.tar.gz&&qemu-system-i386 -kernel tccboot -initrd…
只需一TCCBOOT, 一64MiB内存 x86机, 大约1s的二十倍时间即可体验.
TCC is distributed under the GNU Lesser General Public License.
tar -xf qemu_tccboot.tar.gz&&qemu-system-i386 -kernel tccboot -initrd…
❤2
duangsuse::Echo
😍 pip install 的rich进度条真的太酷了,怎么就没人把它移植给下载管理器呢?? 同理,bash-completions 其实是包维护者手动弄的, 可是 shell param 就两种模式,GNU甚至连git init这种调用链式都不会搞 这个完全可根据 cli -h 自动生成 bash的开发者也不懂事,list complete 应该用 ./a.sh '-s*' 的形式来查询,这样用户和中间商也能沾点光,而且非常UNIX。 分成什么补齐脚本简直画蛇添足 可能它们在写python里自带的功能,还是太忙了。…
duangsuse::Echo
现在随便一个两年经验的SDE开发都能做有双向tcp/http支持和窗口canvas的LLVM编程语言了
https://chat.librechat.ai/share/F1yNVzu4uKs77k4oVidTW #plt #lua
P3: 神了,这下大佬竟是我自己是吧? 也就看个乐呵。 🦞
其实我的要求也是很高的…… 新语言并没有【解决问题】。 💭
P3: 神了,这下大佬竟是我自己是吧? 也就看个乐呵。 🦞
其实我的要求也是很高的…… 新语言并没有【解决问题】。 💭
duangsuse::Echo
我很好奇Scala现在的普及程度。它并没有像Clojure那样消亡
#Haskell 们长期连fmap就是现代H5里的derive()变量这点都没还原好。
直接把Promise弄成不人不鬼的 IO Monad,然后集合类不可变到处Lens(如同Rust的Rc RefCell套壳),结果还不如Svelte。都是回调链表,函数式的功能性和性能就拉胯一节, 不活该被淘汰么
安全${内插}和 o?.nulToNul 这些都属于是极其容易但价值高到夸张的, 所谓的 #> #| bash语法(自定义DSL)与之相比算不了什么。
究竟是天真到什么地步,会觉得mixfix生态位不尴尬? 可以bash或shadertoy里测试,为什么要用Scala写bash?能自动补齐? 需要检查pipe的类型吗?
Li Haoyi 的成功,和他所有库(os-lib, requests-scala 等)的流行,恰恰是因为他回归了Pythonic,利用了JVM上的生态位(kt太卡 Groovy太拉),但是native/js的scala支持咋样我就不说了。 我只能说, tstl (js2lua) 比较成功,这取决于SDK的阻力和output是否够原生。交叉到wasm上都不一定能有好果子吃
🤔 #Lua 其实是个非常奇怪的语言,它的迭代类似于range和JS整数键名的杂种,从1开始数,len和not运算也长的诡异,但只凭效仿SQLite就搞得许多lib(尤其是NVim/Wayland世界)不得不兼容它,虽然效果像H5兼容WASM那样是良善的
#js #FP #ai探讨
“这玩意儿就像 Excel 里的公式往下拉”
直接把Promise弄成不人不鬼的 IO Monad,然后集合类不可变到处Lens(如同Rust的Rc RefCell套壳),结果还不如Svelte。都是回调链表,函数式的功能性和性能就拉胯一节, 不活该被淘汰么
安全${内插}和 o?.nulToNul 这些都属于是极其容易但价值高到夸张的, 所谓的 #> #| bash语法(自定义DSL)与之相比算不了什么。
它很酷,能在特定场景下让代码看起来更“漂亮”或更“贴近领域语言”。 但是让我来选,我会毫不犹豫把${}和parserc作为一等公民,而operator重载和infix作为次要的。
究竟是天真到什么地步,会觉得mixfix生态位不尴尬? 可以bash或shadertoy里测试,为什么要用Scala写bash?能自动补齐? 需要检查pipe的类型吗?
Li Haoyi 的成功,和他所有库(os-lib, requests-scala 等)的流行,恰恰是因为他回归了Pythonic,利用了JVM上的生态位(kt太卡 Groovy太拉),但是native/js的scala支持咋样我就不说了。 我只能说, tstl (js2lua) 比较成功,这取决于SDK的阻力和output是否够原生。交叉到wasm上都不一定能有好果子吃
🤔 #Lua 其实是个非常奇怪的语言,它的迭代类似于range和JS整数键名的杂种,从1开始数,len和not运算也长的诡异,但只凭效仿SQLite就搞得许多lib(尤其是NVim/Wayland世界)不得不兼容它,虽然效果像H5兼容WASM那样是良善的
#js #FP #ai探讨
duangsuse::Echo
#js #web React direct GPU https://github.com/remorses/gpuix GPUI is an immediate-mode UI framework — it rebuilds the entire element tree every frame. Instead of fighting this, GPUIX embraces it: React reconciler detects a state change and queues host mutations…
#vibe 感觉现在真是每个星期都能找到值得学习的项目,但是又没有在做什么。
这两天写了个Vim #lua 配置
正好把之前的 https://t.me/dsuse/22874 说法 实现了一下…… 我的天,还真是 iframe in Vim 😅
虽然整体设计不方便交流,但小细节确实非常搞笑(高效)。 唉,我是否也该变成楼上那种monorepo干三年的大佬呢?
还是要保持码场自由人的传统呢? ……
这两天写了个Vim #lua 配置
正好把之前的 https://t.me/dsuse/22874 说法 实现了一下…… 我的天,还真是 iframe in Vim 😅
虽然整体设计不方便交流,但小细节确实非常搞笑(高效)。 唉,我是否也该变成楼上那种monorepo干三年的大佬呢?
还是要保持码场自由人的传统呢? ……
Telegram
duangsuse::Echo
#post #design 换购思维:面对编辑框的你,不需要证明自己会做
awrit 项目是一个有趣(而且对Vim用户有用)的w3m浏览器升级版。
放到以前我会Star,甚至fork(然后啥都不干)
可现在我只会记住:它平替了什么,它依赖什么API(键鼠屏幕的flow),数据流有哪些typing,哦是electron而非CEF。我甚至只看截图而懒得运行。
——你看, This repository was archived by the owner on Apr 25, 2026. It is…
awrit 项目是一个有趣(而且对Vim用户有用)的w3m浏览器升级版。
放到以前我会Star,甚至fork(然后啥都不干)
可现在我只会记住:它平替了什么,它依赖什么API(键鼠屏幕的flow),数据流有哪些typing,哦是electron而非CEF。我甚至只看截图而懒得运行。
——你看, This repository was archived by the owner on Apr 25, 2026. It is…