-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
2,001 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
from capstone import * | ||
from capstone.x86 import * | ||
|
||
|
||
from ctopy import * | ||
|
||
# Basic code.. | ||
|
||
codeC = ''' | ||
#include "environment.h" | ||
void func() { | ||
%s}\n | ||
int main() { | ||
} | ||
''' | ||
|
||
''' Just load bytes in desired range ''' | ||
def loadCode(filename, start, stop): | ||
f = open(filename, 'rb') | ||
code = f.read() | ||
return code[start:stop] | ||
|
||
class CodeGenerator: | ||
def __init__(self, name, start, stop, flags): | ||
self.code = loadCode(name, start, stop) | ||
self.cCode = '' | ||
|
||
# Instruction lookup | ||
self.cinstr = { | ||
'mov' : mov, | ||
'movzx' : movzx, | ||
'movsx' : movzx, | ||
'cdqe' : cdqe, | ||
'sub' : sub, | ||
'add' : add, | ||
'inc' : inc, | ||
'dec' : dec, | ||
'cmp' : cmp, | ||
'jmp' : jmp, | ||
'jne' : jne, | ||
'je' : je, | ||
'jnb' : jnb, | ||
'jb' : jb, | ||
'jbe' : jbe | ||
} | ||
|
||
self.jumps = ['jmp', 'je', 'jne', 'jz', 'jnz', 'jnb', 'jb', 'jbe'] | ||
self.usedFlags = flags | ||
|
||
# Init capstone | ||
self.cs = Cs(CS_ARCH_X86, CS_MODE_64) | ||
self.cs.detail = True | ||
self.ctopy = [x for x in self.cs.disasm(self.code, 0)] | ||
|
||
self.jumpPlaces = {} | ||
self.checkJumps() | ||
|
||
# go go go | ||
self.generate() | ||
|
||
''' Just fill C template ''' | ||
def getAsC(self): | ||
return codeC % self.cCode | ||
|
||
''' Every jump must have place to jump, | ||
here we check, that every jump has place, | ||
if code is self-modyifing or jumps in middle of instruction | ||
then this method will fail | ||
''' | ||
def checkJumps(self): | ||
for instr in self.ctopy: | ||
|
||
# Is it jump? | ||
if instr.mnemonic in self.jumps: | ||
|
||
# Yes, so get address | ||
addr = int(instr.operands[0].imm) | ||
found = False | ||
|
||
# Check existence of target instruction | ||
for _instr in self.ctopy: | ||
if _instr.address == addr: | ||
found = True | ||
self.jumpPlaces[addr] = True | ||
break | ||
|
||
if not found: | ||
print("Jump to nonexisting instr (Or jump in instr middle)...\nQuitting...") | ||
exit(0) | ||
|
||
''' Go over each instruction in range ''' | ||
def generate(self): | ||
for inst in self.ctopy: | ||
|
||
# If we will jump to this instruction | ||
# Add label for goto | ||
if inst.address in self.jumpPlaces: | ||
self.emit('_%x:' % (inst.address), indent=0) | ||
|
||
# Operands is list of ops, 0, 1, 2 (may more) ops | ||
ops = [x for x in inst.operands] | ||
args = [self.buildOperand(inst, x) for x in ops] | ||
|
||
#print('%x: %s %s -> %s' % (inst.address, inst.mnemonic, inst.op_str, '') ) | ||
|
||
# check is available | ||
if inst.mnemonic not in self.cinstr: | ||
print("Instruction not found...\nQuitting...") | ||
exit(0) | ||
|
||
# process instruction | ||
self.cinstr[ inst.mnemonic ](*args, inst, self) | ||
|
||
''' | ||
Create Operand | ||
''' | ||
def buildOperand(self, instr, operand): | ||
type = operand.type | ||
|
||
# eg. regs.eax | ||
if type == X86_OP_REG: | ||
return Operand(type, instr.reg_name(operand.reg), operand.size) | ||
|
||
# eg. rax + rbx * 1 - 0x13 | ||
if type == X86_OP_MEM: | ||
baseReg = instr.reg_name(operand.mem.base) | ||
displacement = operand.mem.disp | ||
index, scale = (operand.mem.index, operand.mem.scale) | ||
out = baseReg | ||
|
||
if index: | ||
out += '+' + instr.reg_name(index) + '*' + str(scale) | ||
|
||
if displacement: | ||
if displacement < 0: out += '-' | ||
if displacement > 0: out += '+' | ||
out += str(abs(displacement)) | ||
|
||
return Operand(type, out, operand.size) | ||
|
||
# eg. 0x10 | ||
if type == X86_OP_IMM: | ||
return Operand(type, str(operand.imm), operand.size) | ||
|
||
raise "Unknown type..." | ||
|
||
''' Spaces FTW ''' | ||
def emit(self, data, flags = '', actions = '', comment = '', indent = 1): | ||
self.cCode += ' ' * indent | ||
self.cCode += data + '; ' | ||
|
||
# Append comment | ||
if len(comment): | ||
self.cCode += '// ' + comment + '\n' | ||
|
||
# Check is flag used, and append | ||
if len(flags): | ||
for (id, flag) in flags: | ||
if id in self.usedFlags: | ||
self.cCode += (' ' * indent) + ' ' + flag + ';\n' | ||
|
||
# Add actions, executed after setting flags | ||
if len(actions): | ||
for action in actions: | ||
self.cCode += (' ' * indent) + ' ' + action + ';\n' | ||
|
||
if len(comment) == 0 and len(flags) == 0: | ||
self.cCode += '\n' | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#!/usr/bin/python3 | ||
|
||
from CodeGenerator import * | ||
from argparse import * | ||
from os import system | ||
|
||
argp = ArgumentParser() | ||
argp.add_argument("-f", help="File", dest="src_name") | ||
argp.add_argument("-o", help="Output C filename", default='out.c', dest="out_name") | ||
argp.add_argument("-b", help="Begin offset", default=0, dest="begin_off") | ||
argp.add_argument("-e", help="End offset", default=0, dest="end_off") | ||
argp.add_argument("-use-flags", help="Select flags to use", default='czao', dest="flags_used") | ||
|
||
|
||
args = vars(argp.parse_args()) | ||
|
||
filename = args['src_name'] | ||
flagsUsed = [x for x in args['flags_used']] | ||
begin, end = (int(args['begin_off'], 16), int(args['end_off'], 16) ) | ||
|
||
if filename == None: | ||
argp.print_help() | ||
exit(0) | ||
|
||
cg = CodeGenerator(filename, begin, end, flagsUsed) | ||
|
||
cCode = cg.getAsC() | ||
|
||
out = open('out.c', 'wb') | ||
out.write(bytes(cCode, encoding='ascii')) | ||
out.close() | ||
|
||
print('==== translated... ====') | ||
print(cCode) | ||
|
||
#system("gcc out.c -o out") | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from capstone import * | ||
from capstone.x86 import * | ||
|
||
# Alias lookup for casting registers. | ||
# For example: eax -> al | ||
regsSize = [ | ||
[ ['rax', 'eax', 'ax', 'al', 'ah'], {1:'al', 2:'ax', 4:'eax', 8:'rbx'} ], | ||
[ ['rbx', 'ebx', 'bx', 'bl', 'bh'], {1:'bl', 2:'bx', 4:'ebx', 8:'rbx'} ], | ||
[ ['rcx', 'ecx', 'cx', 'cl', 'ch'], {1:'cl', 2:'cx', 4:'ecx', 8:'rcx'} ], | ||
[ ['rdx', 'edx', 'dx', 'dl', 'dh'], {1:'dl', 2:'dx', 4:'edx', 8:'rdx'} ] | ||
] | ||
|
||
dataTypes = { | ||
1 : 'uint8_t', | ||
2 : 'uint16_t', | ||
4 : 'uint32_t', | ||
8 : 'uint64_t' | ||
} | ||
|
||
class Operand: | ||
def __init__(self, type, value, size): | ||
self.type = type | ||
self.value = value | ||
self.sizeBytes = size | ||
self.sizeBits = size * 8 | ||
|
||
def getAsMemoryRef(self, size = 0): | ||
if size != 0: | ||
dataType = dataTypes[size] | ||
else: | ||
dataType = dataTypes[self.sizeBytes] | ||
|
||
# Type other than MEM, so this will propably not compile | ||
if self.type != X86_OP_MEM: | ||
return "_no_no_no_" | ||
|
||
return 'MEMORY(%s, %s)' % (dataType, self.value) | ||
|
||
def getAsRegImm(self, size = 0): | ||
if not size: | ||
size = self.sizeBytes | ||
for r in regsSize: | ||
if self.value in r[0]: | ||
return r[1][size] | ||
|
||
# Propably imm | ||
return self.value | ||
|
||
def getValue(self, size = 0): | ||
if self.type == X86_OP_MEM: | ||
return self.getAsMemoryRef(size) | ||
elif self.type == X86_OP_IMM or self.type == X86_OP_REG: | ||
return self.getAsRegImm(size) | ||
|
||
raise '!!!' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
from capstone import * | ||
from capstone.x86 import * | ||
from Operand import * | ||
|
||
# Overflow flag mask | ||
ofMask = { | ||
1 : 0x80, | ||
2 : 0x8000, | ||
4 : 0x80000000, | ||
8 : 0x8000000000000000 | ||
} | ||
|
||
''' | ||
Instructions in C implementation | ||
''' | ||
|
||
def mov(left, right, inst, cg): | ||
cg.emit('%s = %s' % (left.getValue(), right.getValue()) , | ||
comment = (inst.mnemonic + ' ' + inst.op_str)) | ||
|
||
def movzx(left, right, inst, cg): | ||
cg.emit('%s = 0, %s = %s' % (left.getValue(8), left.getValue(), right.getValue()), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)) | ||
|
||
def sub(left, right, inst, cg, isCmp = False): | ||
sizeBits, sizeBytes = (left.sizeBits, left.sizeBytes) | ||
lVal, rVal = (left.getValue(), right.getValue()) | ||
|
||
if isCmp: | ||
actions = [] | ||
else: | ||
actions = ['%s = tmp%s' % (lVal, sizeBits)] | ||
|
||
cg.emit('TMP%s(%s, -, %s)' % (sizeBits, lVal, rVal), | ||
flags = [ | ||
['c', 'SET_CF_SUB(%s, %s)' % (lVal, rVal)], | ||
['z', 'SET_ZF(%s)' % (sizeBits)], | ||
['a', 'SET_AF_0(%s, %s)' % (left.getValue(1), right.getValue(1))], | ||
['o', 'SET_OF_SUB(%s, %s, %s, %s)' % (lVal, rVal, sizeBits, hex(ofMask[sizeBytes]) )] | ||
], | ||
actions = actions, | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); | ||
|
||
|
||
def add(left, right, inst, cg): | ||
sizeBits, sizeBytes = (left.sizeBits, left.sizeBytes) | ||
lVal, rVal = (left.getValue(), right.getValue()) | ||
|
||
cg.emit('TMP%s(%s, +, %s)' % (sizeBits, lVal, rVal), | ||
flags = [ | ||
['c', 'SET_CF_ADD(%s, %s)' % (sizeBits, lVal)], | ||
['z', 'SET_ZF(%s)' % (sizeBits)], | ||
['a', 'SET_AF_0(%s, %s)' % (left.getValue(1), right.getValue(1))], | ||
['o', 'SET_OF_ADD(%s, %s, %s, %s)' % (lVal, rVal, sizeBits, hex(ofMask[sizeBytes]) )] | ||
], | ||
actions = [ | ||
'%s = tmp%s' % (lVal, sizeBits) | ||
], | ||
comment = (inst.mnemonic + ' ' + inst.op_str)) | ||
|
||
|
||
def inc(left, inst, cg): | ||
sizeBits, sizeBytes = (left.sizeBits, left.sizeBytes) | ||
lVal, rVal = left.getValue(), '1' | ||
|
||
cg.emit('TMP%s(%s, +, %s)' % (sizeBits, lVal, rVal), | ||
flags = [ | ||
['z', 'SET_ZF(%s)' % (sizeBits)], | ||
['a', 'SET_AF_INC(%s)' % (sizeBits)], | ||
['o', 'SET_OF_INC_DEC_NEG(%s, %s)' % (sizeBits, hex(ofMask[sizeBytes]) )], | ||
], | ||
actions = [ | ||
'%s = tmp%s' % (lVal, sizeBits) | ||
], | ||
comment = (inst.mnemonic + ' ' + inst.op_str)) | ||
|
||
|
||
def dec(left, inst, cg): | ||
sizeBits, sizeBytes = (left.sizeBits, left.sizeBytes) | ||
lVal, rVal = left.getValue(), '1' | ||
|
||
cg.emit('TMP%s(%s, -, %s)' % (sizeBits, lVal, rVal), | ||
flags = [ | ||
['z', 'SET_ZF(%s)' % (sizeBits)], | ||
['a', 'SET_AF_DEC(%s)' % (sizeBits)], | ||
['o', 'SET_OF_INC_DEC_NEG(%s, %s)' % (sizeBits, hex(ofMask[sizeBytes]-1) )], | ||
], | ||
actions = [ | ||
'%s = tmp%s' % (lVal, sizeBits) | ||
], | ||
comment = (inst.mnemonic + ' ' + inst.op_str)) | ||
|
||
|
||
def cdqe(inst, cg): | ||
cg.emit('// cdqe not implemented yet') | ||
|
||
def xor(left, right, inst, cg): | ||
pass | ||
|
||
def cmp(left, right, inst, cg): | ||
# cmp is sub without setting value | ||
sub(left, right, inst, cg, True) | ||
|
||
def jmp(op, inst, cg): | ||
cg.emit('goto _%x' % (int(op.value)), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); | ||
|
||
def jne(op, inst, cg): | ||
cg.emit('if(!zf)\n goto _%x' % (int(op.value)), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); | ||
|
||
def je(op, inst, cg): | ||
cg.emit('if(zf)\n goto _%x' % (int(op.value)), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); | ||
|
||
def jb(op, inst, cg): | ||
cg.emit('if(cf)\n goto _%x;' % (int(op.value)), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); | ||
|
||
def jbe(op, inst, cg): | ||
cg.emit('if(cf == 1 || zf == 1)\n goto _%x' % (int(op.value)), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); | ||
|
||
def jnb(op, inst, cg): | ||
cg.emit('if(!cf)\n goto _%x;' % (int(op.value)), | ||
comment = (inst.mnemonic + ' ' + inst.op_str)); |
Oops, something went wrong.