VMP3 - Lua support
Posted: Thu Mar 05, 2015 1:52 pm
First of all, I really like the new Lua scripting support. It opens up a lot of interesting usage scenarios. There are a few minor things that could still be improved.
C is 0-based, while Lua is 1-based. Thus if I do "for i = 1, obj:size() do obj:item(i)..." in Lua, then I'll access an invalid index.
Accessing an invalid index crashes VMP, so e.g. vmprotect.core():inputFile():item(100):functions()
I think there should be a check there that throws a Lua error in that case.
Aside from that it'd be really convenient to access everything 1-based, like in other Lua scripts.
The next thing is that the overall data access is a bit inconvenient. So to print the name of the input file I have to write
This could easily be converted to plain table data access, so it works like this:
Here is a quick & dirty utility function that wraps the vmprotect object to work that way:
Of course it'd be way more efficient to have this in the official API, than to add custom wrappers.
This wrapper i.e. doesn't work with array access, so I can't do let alone
However if the official API already returned everything with an __index metatable, potentially even with __pairs and __ipairs, then everything would be really convenient and feel like "native" Lua.
Currently the returned userdata only has a metatable that supports calling functions.
Aside from that I also have a general usage question. I don't need code for that, but would just like to know if this is the way to do it.
Let's assume I want to automatically add all functions that have "_secure" in their name and have a length >= 5 byte.
Everything that can be accessed via mapFunctions has a size of 0, at least if it's a function.
So I'll have to add all functions in the mapFile to the project (if they fit the name pattern), and then traverse the list of added functions. Only then I can get the size of the function, xrefs, etc. So if it doesn't fit I'll have to remove it. I guess there's some overhead in case I intend to do something like that with 10000+ functions that need to be checked?
Btw: Where did VMProtector.AddByAddress() go?
Last but not least I have a suggestion which might be a really nice killer feature. It requires some time to be added, even though some features of the existing mutation engine can probably be re-used: The list of instructions in the added function list is currently read only. It'd be great to be able to modify those instructions and to even insert new instructions (without breaking relative jumps, jump tables, etc of course). That way it'd be possible to have custom mutation add-ins that are executed as a pre-pass.
C is 0-based, while Lua is 1-based. Thus if I do "for i = 1, obj:size() do obj:item(i)..." in Lua, then I'll access an invalid index.
Accessing an invalid index crashes VMP, so e.g. vmprotect.core():inputFile():item(100):functions()
I think there should be a check there that throws a Lua error in that case.
Aside from that it'd be really convenient to access everything 1-based, like in other Lua scripts.
The next thing is that the overall data access is a bit inconvenient. So to print the name of the input file I have to write
Code: Select all
print(vmprotect.core():inputFile():name())
Code: Select all
print(vmprotect.core.inputFile.name)
Code: Select all
local WrapUserdata
local Meta = {
__index = function(_t, _k)
local func = _t.__UD[_k]
assert(func, k)
local result = func(_t.__UD)
if type(result) == "userdata" then
return WrapUserdata(result)
else
return result
end
end,
__newindex = function()
error("Please don't write to the API tables")
end
}
function WrapUserdata(_UD)
local t = {__UD = _UD}
setmetatable(t, Meta)
return t
end
local _vmprotect = WrapUserdata(vmprotect)
print(_vmprotect.core.inputFile.name)
This wrapper i.e. doesn't work with array access, so I can't do
Code: Select all
vmprotect.core.inputFile.item[1].functions
Code: Select all
for i, file in ipairs(vmprotect.core.inputFile.item) do
Currently the returned userdata only has a metatable that supports calling functions.
Aside from that I also have a general usage question. I don't need code for that, but would just like to know if this is the way to do it.
Let's assume I want to automatically add all functions that have "_secure" in their name and have a length >= 5 byte.
Everything that can be accessed via mapFunctions has a size of 0, at least if it's a function.
So I'll have to add all functions in the mapFile to the project (if they fit the name pattern), and then traverse the list of added functions. Only then I can get the size of the function, xrefs, etc. So if it doesn't fit I'll have to remove it. I guess there's some overhead in case I intend to do something like that with 10000+ functions that need to be checked?
Btw: Where did VMProtector.AddByAddress() go?
Last but not least I have a suggestion which might be a really nice killer feature. It requires some time to be added, even though some features of the existing mutation engine can probably be re-used: The list of instructions in the added function list is currently read only. It'd be great to be able to modify those instructions and to even insert new instructions (without breaking relative jumps, jump tables, etc of course). That way it'd be possible to have custom mutation add-ins that are executed as a pre-pass.