-
Notifications
You must be signed in to change notification settings - Fork 207
Expand file tree
/
Copy pathNumbersToExpressions.lua
More file actions
218 lines (188 loc) · 5.83 KB
/
Copy pathNumbersToExpressions.lua
File metadata and controls
218 lines (188 loc) · 5.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
-- This Script is Part of the Prometheus Obfuscator by levno-710
--
-- NumbersToExpressions.lua
--
-- This Script provides an Obfuscation Step, that converts Number Literals to expressions.
-- This step can now also convert numbers to different representations!
-- Supported representations: hex, binary, scientific, normal. Please note that binary is only supported in Lua 5.2 and above.
unpack = unpack or table.unpack
local Step = require("prometheus.step")
local Ast = require("prometheus.ast")
local visitast = require("prometheus.visitast")
local util = require("prometheus.util")
local logger = require("logger")
local AstKind = Ast.AstKind
local SAFE_INT_LIMIT = jit and math.huge or 2^53
local MAX_VAL = jit and math.huge or 2^54
local NumbersToExpressions = Step:extend()
NumbersToExpressions.Description = "This Step Converts number Literals to Expressions"
NumbersToExpressions.Name = "Numbers To Expressions"
NumbersToExpressions.SettingsDescriptor = {
Threshold = {
type = "number",
default = 1,
min = 0,
max = 1,
},
InternalThreshold = {
type = "number",
default = 0.2,
min = 0,
max = 0.8,
},
NumberRepresentationMutation = {
type = "boolean",
default = false,
-- NOTE: This alias is a legacy misspelling preservation.
-- Please don't remove it.
aliases = { "NumberRepresentationMutaton" },
},
AllowedNumberRepresentations = {
type = "table",
default = {"hex", "scientific", "normal"},
values = {"hex", "binary", "scientific", "normal"},
},
}
local function generateModuloExpression(n)
local rhs = n + math.random(1, 2^24)
local multiplier = math.random(1, 2^8)
local lhs = n + (multiplier * rhs)
return lhs, rhs
end
local function contains(table, value)
for _, v in ipairs(table) do
if v == value then
return true
end
end
return false
end
function NumbersToExpressions:init(_)
self.ExpressionGenerators = {
function(val, depth) -- Addition
local val2 = math.random(-2 ^ 20, 2 ^ 20)
local diff = val - val2
if tonumber(tostring(diff)) + tonumber(tostring(val2)) ~= val then
return false
end
return Ast.AddExpression(
self:CreateNumberExpression(val2, depth),
self:CreateNumberExpression(diff, depth),
false
)
end,
function(val, depth) -- Subtraction
local val2 = math.random(-2 ^ 20, 2 ^ 20)
local diff = val + val2
if tonumber(tostring(diff)) - tonumber(tostring(val2)) ~= val then
return false
end
return Ast.SubExpression(
self:CreateNumberExpression(diff, depth),
self:CreateNumberExpression(val2, depth),
false
)
end,
function(val, depth) -- Modulo
if val > MAX_VAL then return false end
local lhs, rhs = generateModuloExpression(val)
if lhs > SAFE_INT_LIMIT or rhs > SAFE_INT_LIMIT then return false end
if tonumber(tostring(lhs)) % tonumber(tostring(rhs)) ~= val then
return false
end
return Ast.ModExpression(
self:CreateNumberExpression(lhs, depth),
self:CreateNumberExpression(rhs, depth),
false
)
end,
}
end
function NumbersToExpressions:CreateNumberExpression(val, depth)
if depth > 0 and math.random() >= self.InternalThreshold or depth > 15 then
local format = self.AllowedNumberRepresentations[math.random(1, #self.AllowedNumberRepresentations)]
if not self.NumberRepresentationMutation then
return Ast.NumberExpression(val)
end
if format == "hex" then
if val ~= math.floor(val) or val < 0 then
return Ast.NumberExpression(val)
end
local hexStr = string.format("0x%X", val)
local result = ""
for i = 1, #hexStr do
local c = hexStr:sub(i, i)
if math.random() > 0.5 then
result = result .. c:upper()
else
result = result .. c:lower()
end
end
return Ast.NumberExpression(result)
end
if format == "binary" then
if val ~= math.floor(val) or val < 0 then
return Ast.NumberExpression(val)
end
local binary = ""
local n = val
if n == 0 then
binary = "0"
else
while n > 0 do
binary = (n % 2) .. binary
n = math.floor(n / 2)
end
end
return Ast.NumberExpression("0b" .. binary)
end
if format == "scientific" then
if val == 0 then
return Ast.NumberExpression(val)
end
local exp = math.floor(math.log10(math.abs(val)))
local mantissa = val / (10 ^ exp)
-- LuaJIT has full double precision support. Meaning we don't need aggressive safety harnesses for LuaJIT.
if jit then
return Ast.NumberExpression(string.format("%.15ge%d", mantissa, exp))
end
local formatStr = string.format("%ge%+d", mantissa, exp)
local concatStr = mantissa .. "e" .. (exp >= 0 and "+" or "") .. exp
local formatVal = loadstring("return " .. formatStr)
local concatVal = loadstring("return " .. concatStr)
local formatResult = formatVal and formatVal()
local concatResult = concatVal and concatVal()
local formatErr = formatResult and math.abs(formatResult - val) or math.huge
local concatErr = concatResult and math.abs(concatResult - val) or math.huge
if formatErr > 0 and concatErr > 0 then
return Ast.NumberExpression(val)
end
local useFormat = formatErr <= concatErr
return Ast.NumberExpression(useFormat and formatStr or concatStr)
end
if format == "normal" then
return Ast.NumberExpression(val)
end
end
local generators = util.shuffle({ unpack(self.ExpressionGenerators) })
for _, generator in ipairs(generators) do
local node = generator(val, depth + 1)
if node then
return node
end
end
return Ast.NumberExpression(val)
end
function NumbersToExpressions:apply(ast)
if contains(self.AllowedNumberRepresentations, "binary") then
logger:warn("Warning: Binary representation is only supported in Lua 5.2 and above!")
end
visitast(ast, nil, function(node, _)
if node.kind == AstKind.NumberExpression then
if math.random() <= self.Threshold then
return self:CreateNumberExpression(node.value, 0)
end
end
end)
end
return NumbersToExpressions