Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
hanicraft authored Oct 30, 2022
1 parent 596cf30 commit f7b3410
Show file tree
Hide file tree
Showing 7 changed files with 2,001 additions and 0 deletions.
172 changes: 172 additions & 0 deletions Universal C Decompiler/Decompiler/CodeGenerator.py
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'



40 changes: 40 additions & 0 deletions Universal C Decompiler/Decompiler/Decompile.py
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")




56 changes: 56 additions & 0 deletions Universal C Decompiler/Decompiler/Operand.py
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 '!!!'

126 changes: 126 additions & 0 deletions Universal C Decompiler/Decompiler/ctopy.py
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));
Loading

0 comments on commit f7b3410

Please sign in to comment.