I know this should be in the programmers section, but no one reads that o_0 and most of the programmers come over to general anyway.
So, I have come to the conclusion after lots and lots of thinking and philosophizing that you cannot take the raw executable image and generate real polymorphic code from it. The problem is that there simply isn't enough data\information about the code given to the compiler. I mean, you can swap registers, replace a couple instructions with something in a database, use some junk-code, but this isn't real polymorphism. We need a method for creating real polymorphic code. And! I have come to a solution (tell me what you guys think.)
I figured that languages like C or C++ simply do not give the compiler enough meta-data to actually generate polymorphic code. What I mean by this is you cannot organize code dependancy. I.e a function
like this:
Code:
void init()
{
loadX();
loadY();
loadZ();
}
Even though none of these functions depend on one anothers execution, the compiler is likely to organize them in chronological order (unless optimization can figure out that they aren't dependant on one another, in which case it will be consistant with the same optimization configuration (which is no better)). Figuring out whether they are or aren't dependant on one another is virtually impossible to do programatically (i.e, we need the programmer to tell the compiler this.)
So, I came to the conclusion that a new language & compiler must be written. The language has to have the ability for the user to define function dependancy, junk-code or signature tables, etc... This is A LOT of work for the programmer, however a platform can be worked from to relief some of the work. Also note that this would be for small pieces of malicious software that try to evade anti-virus software or for kernel-mode rootkits which duplicate themselves on to remote machines. So, the software will probably be more or less primitive and low-level which will allow one to adopt a procedural language's syntax like that in C or something simpler like assembly. More complex concepts like objects will not be required. Also, giving the programmer more control over how objects behave by forcing them to write their own Virtual Function Tables etc will allow the code to be more polymorphic.
This new syntax will give the compiler many paths to follow when it is compiling code. I.e, consider an add function might look something like this
Code:
dword add(dword x, dword y)
{
container(random, 1)
{
code (true)
{
add x, y
},
code (true)
{
:z=random(y, y+10)
(inc x )*z
sub x, z
}
}
}
This seems confusing at first, and it is, but notice how it is a lot more flexible. You define a function 'add'. Every function can consist of code or data defined in a container. Theoretically (there will probably be more, but for now) there are two arguments that must be given when creating a container
Code:
contianer [optional, name] ([order or segments], [Cycles])
{
[Segments...]
}
name - I have a lot of ideas for this, but to simplify the process, I won't use it in this example.
order of segments - can be random (all segments are ordered randomly) or can be procedural (segments are compiled in the order they appear). If it is procedural, the cycles parameter is ignored.
Cycles - Number of times to repeat segment choosing (i.e if it is 2, it will find two random segments in the container to use)
Each segment can be defined as data or code. I won't describe data because it I haven't thoughy it up yet (however the data section will also describe how the data is obstructed and describe routines that must be used to access byte x of a data structure.)
For code
Code:
code ([condition that must be true for this segment to be selected])
{
:compile-time variables (i.e variables that can be used to generate code but aren't actually compiled in to the file.)
code in assembly (well, kind of assembly. Similar but more syntactic sugar to make more dynamic code-generation).
}
Ofcourse, even with all this meta-data, the compiler really cannot generate dynamic enough code; so that is where signature trees come in (they're used to create junk-code as well to make more dynamic code generation.)
an example of a signature tree would be:
Code:
sig-tree
{
add x, c
{
container(random, random(1, 10))
{
code(true)
{
xor x, 1F
xor x, 1F
}
}
container(procedural)
{
code(true)
{
xor x, x
}
container(random, c)
{
inc x
}
}
}
mov x, y
{
container(random, 1)
{
code(true)
{
xor y, 1F
xor x, x
inx x
xor x, ff
xor x, ff
dec x
mov x, y
xor x, 1F
},
{
xor x, x
add x, y
}
}
}
}
Notice how I structured the container in the sig-tree such that contained a sub-container to force xor x, x to be the first expression in the second container. This shows the compiler how different expressions (i.e a mov expression) can be re-expressed to create more dynamic code. These would consist of many instructions, more than just mov. Ofcourse, EVEN THIS isn't enough to create random enough code. The idea is that the code would go through several cycles of this table to make the code look completely different.
Now, when someone does something like this
Code:
int x = add(y, 25);
a simple statement like that can span several lines of code and can be dramatically different per each executable.
When we use the 'add' function in another function, and that function in another, and that in many different places in the code, randomize whether functions are inline or not, it becomes a completely different executable image each time the code is generated.
Finally, the idea is for code to be generated in to meta-code and not nativley executable code; thus we can add a code-generation stub that generates the function on demand (thus running a different path of execution every time it runs) or if performance is an issue (and it shouldn't be because this engine isn't designed with optimization in mind) then you can just do it once before the application's entry-point is entered. Doing so actually might make it less suspicious to the anti-virus software as well - or whatever it is that you're trying to hide your code from.
Watchu think?