JungHyun Kim

Upload source files

No preview for this file type
import serial
from threading import Thread
s = serial.Serial(
port = 'COM3',
baudrate= 9600,
)
print('[+] connected')
buffer = []
def cb_recv():
while True:
l = s.readline().decode(encoding='ascii', errors='ignore')
buffer.append(l)
Thread(target=cb_recv).start()
while True:
if len(buffer) != 0:
for l in buffer:
print('received:', l)
buffer.clear()
inst = input("Input:")
tokens = inst.split(' ')
if tokens[0] == 'i': # inject a code
with open(tokens[1], 'rb') as f:
s.write(f.read())
elif tokens[0] == 's': # input string
type = int(tokens[1])
msg = tokens[2].encode(encoding='ascii')
payload = bytes([len(msg), type]) + msg
print('sent:', payload)
s.write(payload)
elif tokens[0] == 'q': # quit
s.close()
break
\ No newline at end of file
This diff is collapsed. Click to expand it.
angr==9.0.6136
capstone==4.0.2
claripy==9.0.6136
click==6.7
pyserial==3.4
r2pipe==1.5.3
z3-solver==4.8.10.0
\ No newline at end of file
from utils import *
import re
from capstone import *
# 완전히 다른 놈이면 0.000... 이렇게 나오더라
THRESH_HOLD = 0.80
API_ELF_PATH = 'API.ino.elf'
API_DB_PATH = 'sym_func.db'
class RestoreAPI:
def __init__(self, binPath, functionOffsets):
funcs = readFunctionInfoFromElf(API_ELF_PATH)
funcs = self.__refineByDB(funcs)
apiList = {}
angrFuncList = readFunctionInfoFromBin(binPath, functionOffsets)
for func in funcs:
found = self.__findMostSimilarFunction(func, angrFuncList)
if found['prob'] >= THRESH_HOLD:
apiList[found['offset']] = {
'type': func['type'],
'name': func['name']
}
print(found['prob'], hex(found['offset']), func['name'])
print('[*] found api count:', len(apiList))
self.apiList = apiList
def __findMostSimilarFunction(self, src, angrFuncList):
BoB = {'offset': -1, 'prob': 0.0, 'ops': []}
for angrFunc in angrFuncList:
prob = compareFunction(src['ops'], angrFunc['ops'])
if prob > BoB['prob']:
BoB['offset'] = angrFunc['offset']
BoB['prob'] = prob
BoB['ops'] = angrFunc['ops']
return BoB
def __refineByDB(self, funcs):
dbMap = self.__readDB(API_DB_PATH)
ret = []
for func in funcs:
info = self.__findInfoByName(dbMap, func['name'])
if info == None:
continue
name = func['name']
name = name[name.find('.')+1:]
func['name'] = name
print(f'db: {name}')
func['type'] = info['type']
ret.append(func)
return ret
def __readDB(self, dbPath):
ret = []
currentType = None
with open(dbPath, 'rt') as f:
for s in f.readlines():
s = s.strip(' \n')
if s == '':
continue
if s[0] == '#':
continue
t = re.findall('^!\((.+)\)$', s)
if len(t) == 1:
currentType = t[0]
else:
# it must be substring of function name!
ret.append({'name': s, 'type': currentType})
return ret
def __findInfoByName(self, dbMap, name):
for v in dbMap:
if v['name'] in name:
return v
return None
def restore(self):
return self.apiList
\ No newline at end of file
###################################################
!(no_return)
###################################################
init
Print.write
Print::write
# those are too short for using in comparison.
# they can cause False-Positive.
#Print.print
#Print::print
#Print::println
printNumber
# system functions
CLK_
SystemCoreClockUp
libc_init_array
HardwareSerial::write
#HardwareSerial::flush
digitalWrite
###################################################
!(return_sym)
###################################################
digitalRead
###################################################
!(return_zero)
###################################################
###################################################
!(return_one)
###################################################
HardwareSerial::available
###################################################
!(on_read)
###################################################
HardwareSerial.read
\ No newline at end of file
import r2pipe
import angr
import cle
import json
def loadBinary(path):
with open(path, 'rb') as f:
return f.read()
def getInst(block):
inst = block.capstone.insns[0]
# size, address
# mnemonic: opcode
# op_str: operand
return inst.mnemonic, inst.op_str
def getInsts(block):
ret = []
for inst in block.capstone.insns:
opcode = inst.mnemonic
ret.append(opcode)
return ret
# size, address
# mnemonic: opcode
# op_str: operand
def readFunctionInfoFromElf(elfPath):
r = r2pipe.open(elfPath, flags=['-2'])
r.cmd('aaa')
ret = []
for f in r.cmd('pdfj @@fcn').split('\n'):
if f == '': continue
f = json.loads(f)
addr = int(f['addr'])
size = int(f['size'])
name = f['name']
ops = []
for v in f['ops']:
if 'opcode' in v:
ops.append(v['opcode'].split(' ')[0])
ret.append({'addr':addr, 'size':size, 'name':name, 'ops':ops})
return ret
def getRadareHandlerByOffsetList(binPath, functionOffsets):
r = r2pipe.open(binPath, ['-2', '-aarm', '-b16', '-m0x0'])
for offset in functionOffsets:
r.cmd(f"s {offset&(~1)}")
r.cmd('aaa')
return r
def readFunctionInfoFromBin(binPath, functionOffsets):
ret = []
r = getRadareHandlerByOffsetList(binPath, functionOffsets)
for f in r.cmd('pdfj @@fcn').split('\n'):
if f == '': continue
f = json.loads(f)
addr = int(f['addr'])
size = int(f['size'])
ops = []
for v in f['ops']:
if 'opcode' in v:
ops.append(v['opcode'].split(' ')[0])
ret.append({'offset':addr, 'size':size, 'name':'none', 'ops':ops})
return ret
def levenshtein(s1, s2, debug=False):
if len(s1) < len(s2):
return levenshtein(s2, s1, debug)
if len(s2) == 0:
return len(s1)
previous_row = range(len(s2) + 1)
for i, c1 in enumerate(s1):
current_row = [i + 1]
for j, c2 in enumerate(s2):
insertions = previous_row[j + 1] + 1
deletions = current_row[j] + 1
substitutions = previous_row[j] + (c1 != c2)
current_row.append(min(insertions, deletions, substitutions))
if debug:
print(current_row[1:])
previous_row = current_row
return previous_row[-1]
def compareFunction(f1, f2):
distance = levenshtein(f1, f2)
return 1.0 - distance / max([len(f1), len(f2)])
def ngram(s, num):
res = []
slen = len(s) - num + 1
for i in range(slen):
#print('a',s)
ss = (s[i], s[i+1])
#ss = s[i:i+num]
res.append(ss)
return res
def diff_ngram(sa, sb, num):
a = ngram(sa, num)
b = ngram(sb, num)
r = []
cnt = 0
for i in a:
for j in b:
if i == j:
cnt += 1
r.append(i)
#return cnt / max([len(a), len(b)]), r
return cnt, r
prob, _ = diff_ngram(f1, f2, 2)
return prob
# readFunctionInfoFromElf('API.ino.elf')
\ No newline at end of file
//
// Global Variables
//
// A flag which determines the input mode.
bool isAdmin = false;
// It may be changed every time the device boots up.
const char PASSWORD[] = "033BD94B1168D7E4F0D644C3C95E35BF";
//
// Definitions
//
#define BUFFER_SIZE 64
struct Packet {
unsigned char size;
unsigned char type;
unsigned char data[BUFFER_SIZE];
};
namespace User {
enum PacketType {
Hello = 0x00,
Auth
};
void onInput(Packet&);
void switchToAdmin();
}
namespace Admin {
enum PacketType {
Hello = 0x00
};
void onInput(Packet&);
}
char recv() {
while(!Serial.available());
return Serial.read();
}
void setup() {
Serial.begin(9600);
Serial.println("[+] Initialized");
}
void loop() {
if(Serial.available()) {
Packet packet;
packet.size = recv();
packet.type = recv();
int i = 0;
while(true) {
if(i >= packet.size) break;
packet.data[i++] = recv();
}
if(isAdmin) {
Admin::onInput(packet);
} else {
User::onInput(packet);
}
}
}
void User::onInput(Packet &packet) {
switch(packet.type) {
case User::PacketType::Hello:
Serial.print("Hello,");
Serial.println((char*)packet.data);
break;
case User::PacketType::Auth:
if(!memcmp(packet.data, PASSWORD, sizeof(PASSWORD))) {
switchToAdmin();
} else {
Serial.println("[*] Invalid password");
}
break;
default:
Serial.print("[*] Invalid packet type: ");
Serial.println(packet.type);
break;
}
}
void Admin::onInput(Packet &packet) {
switch(packet.type) {
case Admin::PacketType::Hello:
Serial.print("You are an admin, ");
Serial.println((char*)packet.data);
break;
default:
Serial.print("[*] Invalid packet type: ");
Serial.println(packet.type);
break;
}
}
void User::switchToAdmin() {
isAdmin = true;
Serial.println("[*] Switched to admin mode");
}
\ No newline at end of file