JungHyun Kim

Upload source files

No preview for this file type
1 +import serial
2 +from threading import Thread
3 +
4 +s = serial.Serial(
5 + port = 'COM3',
6 + baudrate= 9600,
7 +)
8 +print('[+] connected')
9 +buffer = []
10 +def cb_recv():
11 + while True:
12 + l = s.readline().decode(encoding='ascii', errors='ignore')
13 + buffer.append(l)
14 +Thread(target=cb_recv).start()
15 +while True:
16 + if len(buffer) != 0:
17 + for l in buffer:
18 + print('received:', l)
19 + buffer.clear()
20 + inst = input("Input:")
21 + tokens = inst.split(' ')
22 + if tokens[0] == 'i': # inject a code
23 + with open(tokens[1], 'rb') as f:
24 + s.write(f.read())
25 + elif tokens[0] == 's': # input string
26 + type = int(tokens[1])
27 + msg = tokens[2].encode(encoding='ascii')
28 + payload = bytes([len(msg), type]) + msg
29 + print('sent:', payload)
30 + s.write(payload)
31 + elif tokens[0] == 'q': # quit
32 + s.close()
33 + break
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
1 +angr==9.0.6136
2 +capstone==4.0.2
3 +claripy==9.0.6136
4 +click==6.7
5 +pyserial==3.4
6 +r2pipe==1.5.3
7 +z3-solver==4.8.10.0
...\ No newline at end of file ...\ No newline at end of file
1 +from utils import *
2 +import re
3 +from capstone import *
4 +
5 +# 완전히 다른 놈이면 0.000... 이렇게 나오더라
6 +THRESH_HOLD = 0.80
7 +API_ELF_PATH = 'API.ino.elf'
8 +API_DB_PATH = 'sym_func.db'
9 +
10 +class RestoreAPI:
11 + def __init__(self, binPath, functionOffsets):
12 + funcs = readFunctionInfoFromElf(API_ELF_PATH)
13 + funcs = self.__refineByDB(funcs)
14 + apiList = {}
15 + angrFuncList = readFunctionInfoFromBin(binPath, functionOffsets)
16 + for func in funcs:
17 + found = self.__findMostSimilarFunction(func, angrFuncList)
18 + if found['prob'] >= THRESH_HOLD:
19 + apiList[found['offset']] = {
20 + 'type': func['type'],
21 + 'name': func['name']
22 + }
23 + print(found['prob'], hex(found['offset']), func['name'])
24 + print('[*] found api count:', len(apiList))
25 + self.apiList = apiList
26 +
27 + def __findMostSimilarFunction(self, src, angrFuncList):
28 + BoB = {'offset': -1, 'prob': 0.0, 'ops': []}
29 + for angrFunc in angrFuncList:
30 + prob = compareFunction(src['ops'], angrFunc['ops'])
31 + if prob > BoB['prob']:
32 + BoB['offset'] = angrFunc['offset']
33 + BoB['prob'] = prob
34 + BoB['ops'] = angrFunc['ops']
35 + return BoB
36 +
37 + def __refineByDB(self, funcs):
38 + dbMap = self.__readDB(API_DB_PATH)
39 + ret = []
40 + for func in funcs:
41 + info = self.__findInfoByName(dbMap, func['name'])
42 + if info == None:
43 + continue
44 + name = func['name']
45 + name = name[name.find('.')+1:]
46 + func['name'] = name
47 + print(f'db: {name}')
48 + func['type'] = info['type']
49 + ret.append(func)
50 + return ret
51 +
52 + def __readDB(self, dbPath):
53 + ret = []
54 + currentType = None
55 + with open(dbPath, 'rt') as f:
56 + for s in f.readlines():
57 + s = s.strip(' \n')
58 + if s == '':
59 + continue
60 + if s[0] == '#':
61 + continue
62 + t = re.findall('^!\((.+)\)$', s)
63 + if len(t) == 1:
64 + currentType = t[0]
65 + else:
66 + # it must be substring of function name!
67 + ret.append({'name': s, 'type': currentType})
68 + return ret
69 +
70 + def __findInfoByName(self, dbMap, name):
71 + for v in dbMap:
72 + if v['name'] in name:
73 + return v
74 + return None
75 +
76 + def restore(self):
77 + return self.apiList
78 +
...\ No newline at end of file ...\ No newline at end of file
1 +###################################################
2 +!(no_return)
3 +###################################################
4 +init
5 +Print.write
6 +Print::write
7 +# those are too short for using in comparison.
8 +# they can cause False-Positive.
9 +#Print.print
10 +#Print::print
11 +#Print::println
12 +printNumber
13 +# system functions
14 +CLK_
15 +SystemCoreClockUp
16 +libc_init_array
17 +HardwareSerial::write
18 +#HardwareSerial::flush
19 +digitalWrite
20 +
21 +###################################################
22 +!(return_sym)
23 +###################################################
24 +digitalRead
25 +
26 +###################################################
27 +!(return_zero)
28 +###################################################
29 +
30 +###################################################
31 +!(return_one)
32 +###################################################
33 +HardwareSerial::available
34 +
35 +###################################################
36 +!(on_read)
37 +###################################################
38 +HardwareSerial.read
...\ No newline at end of file ...\ No newline at end of file
1 +import r2pipe
2 +import angr
3 +import cle
4 +import json
5 +
6 +def loadBinary(path):
7 + with open(path, 'rb') as f:
8 + return f.read()
9 +
10 +def getInst(block):
11 + inst = block.capstone.insns[0]
12 + # size, address
13 + # mnemonic: opcode
14 + # op_str: operand
15 + return inst.mnemonic, inst.op_str
16 +
17 +def getInsts(block):
18 + ret = []
19 + for inst in block.capstone.insns:
20 + opcode = inst.mnemonic
21 + ret.append(opcode)
22 + return ret
23 + # size, address
24 + # mnemonic: opcode
25 + # op_str: operand
26 +
27 +def readFunctionInfoFromElf(elfPath):
28 + r = r2pipe.open(elfPath, flags=['-2'])
29 + r.cmd('aaa')
30 + ret = []
31 + for f in r.cmd('pdfj @@fcn').split('\n'):
32 + if f == '': continue
33 + f = json.loads(f)
34 + addr = int(f['addr'])
35 + size = int(f['size'])
36 + name = f['name']
37 + ops = []
38 + for v in f['ops']:
39 + if 'opcode' in v:
40 + ops.append(v['opcode'].split(' ')[0])
41 + ret.append({'addr':addr, 'size':size, 'name':name, 'ops':ops})
42 + return ret
43 +
44 +def getRadareHandlerByOffsetList(binPath, functionOffsets):
45 + r = r2pipe.open(binPath, ['-2', '-aarm', '-b16', '-m0x0'])
46 + for offset in functionOffsets:
47 + r.cmd(f"s {offset&(~1)}")
48 + r.cmd('aaa')
49 + return r
50 +
51 +def readFunctionInfoFromBin(binPath, functionOffsets):
52 + ret = []
53 + r = getRadareHandlerByOffsetList(binPath, functionOffsets)
54 + for f in r.cmd('pdfj @@fcn').split('\n'):
55 + if f == '': continue
56 + f = json.loads(f)
57 + addr = int(f['addr'])
58 + size = int(f['size'])
59 + ops = []
60 + for v in f['ops']:
61 + if 'opcode' in v:
62 + ops.append(v['opcode'].split(' ')[0])
63 + ret.append({'offset':addr, 'size':size, 'name':'none', 'ops':ops})
64 + return ret
65 +
66 +def levenshtein(s1, s2, debug=False):
67 + if len(s1) < len(s2):
68 + return levenshtein(s2, s1, debug)
69 +
70 + if len(s2) == 0:
71 + return len(s1)
72 +
73 + previous_row = range(len(s2) + 1)
74 + for i, c1 in enumerate(s1):
75 + current_row = [i + 1]
76 + for j, c2 in enumerate(s2):
77 + insertions = previous_row[j + 1] + 1
78 + deletions = current_row[j] + 1
79 + substitutions = previous_row[j] + (c1 != c2)
80 + current_row.append(min(insertions, deletions, substitutions))
81 +
82 + if debug:
83 + print(current_row[1:])
84 +
85 + previous_row = current_row
86 +
87 + return previous_row[-1]
88 +
89 +def compareFunction(f1, f2):
90 + distance = levenshtein(f1, f2)
91 + return 1.0 - distance / max([len(f1), len(f2)])
92 +
93 + def ngram(s, num):
94 + res = []
95 + slen = len(s) - num + 1
96 + for i in range(slen):
97 + #print('a',s)
98 + ss = (s[i], s[i+1])
99 + #ss = s[i:i+num]
100 + res.append(ss)
101 + return res
102 + def diff_ngram(sa, sb, num):
103 + a = ngram(sa, num)
104 + b = ngram(sb, num)
105 + r = []
106 + cnt = 0
107 + for i in a:
108 + for j in b:
109 + if i == j:
110 + cnt += 1
111 + r.append(i)
112 + #return cnt / max([len(a), len(b)]), r
113 + return cnt, r
114 + prob, _ = diff_ngram(f1, f2, 2)
115 + return prob
116 +
117 +# readFunctionInfoFromElf('API.ino.elf')
...\ No newline at end of file ...\ No newline at end of file
1 +//
2 +// Global Variables
3 +//
4 +// A flag which determines the input mode.
5 +bool isAdmin = false;
6 +// It may be changed every time the device boots up.
7 +const char PASSWORD[] = "033BD94B1168D7E4F0D644C3C95E35BF";
8 +
9 +//
10 +// Definitions
11 +//
12 +
13 +#define BUFFER_SIZE 64
14 +
15 +struct Packet {
16 + unsigned char size;
17 + unsigned char type;
18 + unsigned char data[BUFFER_SIZE];
19 +};
20 +
21 +namespace User {
22 + enum PacketType {
23 + Hello = 0x00,
24 + Auth
25 + };
26 + void onInput(Packet&);
27 + void switchToAdmin();
28 +}
29 +
30 +namespace Admin {
31 + enum PacketType {
32 + Hello = 0x00
33 + };
34 + void onInput(Packet&);
35 +}
36 +
37 +char recv() {
38 + while(!Serial.available());
39 + return Serial.read();
40 +}
41 +
42 +void setup() {
43 + Serial.begin(9600);
44 + Serial.println("[+] Initialized");
45 +}
46 +
47 +void loop() {
48 + if(Serial.available()) {
49 + Packet packet;
50 + packet.size = recv();
51 + packet.type = recv();
52 + int i = 0;
53 + while(true) {
54 + if(i >= packet.size) break;
55 + packet.data[i++] = recv();
56 + }
57 + if(isAdmin) {
58 + Admin::onInput(packet);
59 + } else {
60 + User::onInput(packet);
61 + }
62 + }
63 +}
64 +
65 +void User::onInput(Packet &packet) {
66 + switch(packet.type) {
67 + case User::PacketType::Hello:
68 + Serial.print("Hello,");
69 + Serial.println((char*)packet.data);
70 + break;
71 + case User::PacketType::Auth:
72 + if(!memcmp(packet.data, PASSWORD, sizeof(PASSWORD))) {
73 + switchToAdmin();
74 + } else {
75 + Serial.println("[*] Invalid password");
76 + }
77 + break;
78 + default:
79 + Serial.print("[*] Invalid packet type: ");
80 + Serial.println(packet.type);
81 + break;
82 + }
83 +}
84 +
85 +void Admin::onInput(Packet &packet) {
86 + switch(packet.type) {
87 + case Admin::PacketType::Hello:
88 + Serial.print("You are an admin, ");
89 + Serial.println((char*)packet.data);
90 + break;
91 + default:
92 + Serial.print("[*] Invalid packet type: ");
93 + Serial.println(packet.type);
94 + break;
95 + }
96 +}
97 +
98 +void User::switchToAdmin() {
99 + isAdmin = true;
100 + Serial.println("[*] Switched to admin mode");
101 +}
...\ No newline at end of file ...\ No newline at end of file