forked from ANSSI-FR/polichombr
/
skelenox.py
executable file
·963 lines (831 loc) · 29.9 KB
/
skelenox.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
import string
import os
import time
import httplib
import sqlite3
import urllib
import gzip
from StringIO import StringIO
# if this fail, install libopenssl0.9.8:i386 (on ubuntu x64)
try:
import _hashlib
except:
import hashlib as _hashlib
import idaapi
import idautils
import idc
import atexit
import json
import ssl
from string import lower
# TODO:
# [x] SkelDB
# [x] SkelConn
# [x] SkelSettings
# [ ] Fix upload of sample if it is new
# [ ] Fix note pad destruction when calling exit_skelenox
# [ ] Proper logging
# [ ] Local names (prefix) are not pushed.
settings_filename = "skelsettings.json"
skel_settings = None
skel_db = None
skel_conn = None
last_timestamp = 0
skelhook = None
skelhook_set = None
uihook = None
polihook = None
poli_id = 0
sample_id = 0
crit_backup_file = None
last_saved = 0
backup_file = None
notepadHandle = None
class SkelConfig(object):
"""
Config management
"""
def __init__(self, settings_file):
filename = os.path.dirname(__file__) + "/" + settings_file
self.username = "Anonymous"
self.edit_flag = False
# Network config
self.poli_server = ""
self.poli_port = 80
self.poli_remote_path = ""
self.poli_apikey = ""
self.debug_http = False
self.online_at_startup = None
self.poli_timeout = 5
# Skelenox general config
self.display_subs_info = False
self.int_func_lines_count = 9
self.save_timeout = 10 * 60
# White background, edit to your color scheme preference
self.auto_highlight = 1
self.backgnd_highlight_color = 0xA0A0FF
self.backgnd_std_color = 0xFFFFFF
# Fond noir
# self.backgnd_highlight_color = 0x333333
# self.backgnd_std_color = 0x0
# Notepad
self.notepad_font_name = 'Courier New'
self.notepad_font_size = 9
if os.path.isfile(filename):
print "[+] Loading settings file"
self._do_init(filename)
else:
print "[!] Config file not edited, populating default"
self.populate_default(filename)
self.not_edited(filename)
def not_edited(self, filename):
"""
Error file not edited ;-)
"""
idc.Warning("Please edit the %s file with your settings!" % (filename))
raise EnvironmentError
def _do_init(self, filename):
"""
Loads the settings in JSON file
"""
with open(filename, 'r') as inputfile:
raw_data = inputfile.read()
data = json.loads(raw_data, encoding='ascii')
if data["edit_flag"] is False:
self.not_edited(filename)
else:
for key in data.keys():
setattr(self, key, data[key])
def populate_default(self, filename):
"""
Dumps the default value in JSON in the given filename
"""
data = json.dumps(vars(self), sort_keys=True, indent=4)
with open(filename, 'w') as outfile:
outfile.write(data)
def dump_config(self):
"""
Simply print the config on screen
"""
values = {}
for elem in vars(self).keys():
values[elem] = vars(self)[elem]
print json.dumps(values, sort_keys=True, indent=4)
class SkelConnection(object):
"""
HTTP(S) API management
"""
def __init__(self, poli_server="", poli_port=5000,
remote_path="", poli_apikey="", http_debug=False):
self.http_debug = http_debug
self.remote_path = remote_path
self.api_key = poli_apikey
self.poli_server = poli_server
self.poli_port = poli_port
self.h_conn = None
self.is_online = False
self.ctx = None
def get_online(self):
"""
Connect to the server
"""
try:
self.__do_init()
except Exception as e:
print "[!] Polichombr server seems down"
print e
def __do_init(self):
"""
Initiate connection handle
"""
if self.http_debug is True:
self.h_conn = httplib.HTTPConnection(
self.poli_server, self.poli_port)
else:
self.ctx = ssl._create_unverified_context()
self.h_conn = httplib.HTTPSConnection(
self.poli_server, context=self.ctx)
self.h_conn.connect()
self.is_online = True
def get_offline(self):
"""
Wrapper to close connection
"""
self.close_connection()
def close_connection(self):
"""
Cleanup the connection
"""
if self.h_conn is not None:
self.h_conn.close()
self.is_online = False
def poli_post(self, endpoint="/", data=None):
"""
@arg : endpoint The API target endpoint
@arg : data dictionary
@return : dict issued from JSON
"""
headers = {"Accept-encoding": "gzip, deflate",
"Content-type": "application/json",
"Connection": "keep-alive",
"Accept": "*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Connection": "Keep-Alive"
}
method = "POST"
#data["apikey"] = skelsettings.api_key
json_data = json.dumps(data)
self.h_conn.request(method, endpoint, json_data, headers)
res = self.h_conn.getresponse()
if res.status != 200:
print "[!] Error during request"
contentType = res.getheader("Content-Encoding")
if contentType == "gzip":
buf = StringIO(res.read())
res = gzip.GzipFile(fileobj=buf)
data = res.read()
try:
result = json.loads(data)
except:
print data
raise IOError
return result
def poli_get(self, endpoint="/", data=None):
"""
@arg : endpoint The API target endpoint
@arg : data dictionary
@return : dict issued from JSON
"""
headers = {"Accept-encoding": "gzip, deflate",
"Content-type": "application/json",
"Connection": "keep-alive",
"Accept": "*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Connection": "Keep-Alive",
"X-API-Key": self.api_key
}
method = "GET"
#data["apikey"] = skelsettings.api_key
json_data = json.dumps(data)
self.h_conn.request(method, endpoint, json_data, headers)
res = self.h_conn.getresponse()
if res.status != 200:
print "[!] Error during request"
contentType = res.getheader("Content-Encoding")
if contentType == "gzip":
buf = StringIO(res.read())
res = gzip.GzipFile(fileobj=buf)
data = res.read()
try:
result = json.loads(data)
except:
print data
raise IOError
return result
def push_comment(self, address=0, comment=None):
print "Comment %s sent for address 0x%x" % (comment, address)
if comment is None:
return False
global sample_id
data = {"address": address,
"comment": comment}
endpoint = self.prepare_endpoint('comments')
res = self.poli_post(endpoint, data)
def get_comments(self):
endpoint = self.prepare_endpoint('comments')
res = self.poli_get(endpoint)
return res["comments"]
def get_names(self):
endpoint = self.prepare_endpoint('names')
res = self.poli_get(endpoint)
return res["names"]
def push_name(self, address=0, name=None):
if name is None:
return False
global sample_id
data = {"address": address,
"name": name}
endpoint = self.prepare_endpoint('names')
res = self.poli_post(endpoint, data)
print res
@staticmethod
def prepare_endpoint(action):
global sample_id
return "/api/1.0/samples/" + str(sample_id) + "/" + action + "/"
def checkupdates():
global skel_conn
if skel_conn.is_online is False:
return 0
# on synchro avec le server l'idb courant
if sync_names() == -1:
return -1
# on pousse le cache pour le sample actuel (et au passage on overwrite
# ceux renamed lors de la synchro)
return 0
def pushchange(cmd, param1, param2):
global skel_conn, sample_id
print "[+] " + cmd + " => " + param1 + " :: " + param2 + " -- SENT"
return True
def pushFunctionsNames():
"""
update les noms de fonctions depuis l'idb actuel
"""
global sample_id
for addr in idautils.Functions(idc.MinEA(), idc.MaxEA()):
fname = GetFunctionName(addr)
if fname != "" and not hasSubNoppedPrefix(fname):
if skel_conn.push_name(addr, fname) == -1:
return -1
return 0
def update_ida_hash(sampid=0, polid=0):
"""
genere le hash global et pousse tout sur poli
"""
global sample_id, skel_conn
if skel_conn.is_online is False:
return 0
fHash = ""
if res != []:
for sub in res:
if sub[0] is None:
continue
fHash += sub[0] + ":" + shexst(sub[1]) + ";"
if len(fHash) == 0:
return 0
#data = skel_conn.poli_request("updateIdaHash", [["id", polid]], [["idaSign", fHash]])
return 0
def startup():
"""
Ask for initial synchro
"""
global skel_conn
overwrite = idaapi.askbuttons_c("YES", "NO", "NO",
0,
"Names synchro: do you want to keep your actual subs names?\nYES: keep your actual names (and push them to the server)\nNO: overwrite the actual names with the server's ones")
if overwrite == 1:
if pushFunctionsNames() == -1:
return -1
else:
return sync_names(True)
def execute_comment(comment):
"""
XXX : switch on the comment type
"""
print comment["address"]
idc.MakeRptCmt(
comment["address"],
comment["data"].encode(
'ascii',
'replace'))
print "[x] Added comment %s @0x%x " % (comment["data"], comment["address"])
def sync_names(full_synchro=False):
global sample_id, skel_conn, last_timestamp
if not skel_conn.is_online:
return 0
comments = skel_conn.get_comments()
for comment in comments:
execute_comment(comment)
names = skel_conn.get_names()
for name in names:
if "sub_" in idc.GetTrueName(name["address"]):
print "[x] renaming %s @0x%x as %s" % (idc.GetTrueName(name["address"]), name["address"], name["data"])
idc.MakeName(
name["address"],
name["data"].encode(
'ascii',
'ignore'))
# Here, parse the new commands and execute them
print "[+] IDB synchronized"
return 0
def calc_hash(funcAddr):
"""
# calculer un hash de fonction poli-style
# pas de MD5 pour l'instant, voir plus tard si besoin
"""
global ample_id
func = idaapi.get_func(funcAddr)
if func is None:
return ""
flow = idaapi.FlowChart(f=func)
cur_hash_rev = ""
addrIds = []
cur_id = 1
bb_addr = []
for c in range(0, flow.size):
bb_addr.append(flow.__getitem__(c).startEA)
for c in range(0, flow.size):
cur_basic = flow.__getitem__(c)
cur_hash_rev += shex(cur_basic.startEA) + ":"
addrIds.append((shex(cur_basic.startEA), str(cur_id)))
cur_id += 1
# on regarde si on voit des calls
addr = cur_basic.startEA
blockEnd = cur_basic.endEA
mnem = GetMnem(addr)
while mnem != "":
if mnem == "call":
cur_hash_rev += "c,"
addr = NextHead(addr, blockEnd)
mnem = GetMnem(addr)
if addr != BADADDR:
cur_hash_rev += shex(addr) + ";" + shex(addr) + ":"
addrIds.append((shex(addr), str(cur_id)))
cur_id += 1
else:
addr = NextHead(addr, blockEnd)
mnem = GetMnem(addr)
refs = []
for suc in cur_basic.succs():
refs.append(suc.startEA)
refs.sort()
refsrev = ""
for ref in refs:
refsrev += shex(ref) + ","
if refsrev != "":
refsrev = refsrev[:-1]
cur_hash_rev += refsrev + ";"
# a ce stade, on a des strings de la forme:
# 00000000:00000010,000000020;00000010:c,00000012;00000012:00000020;00000020:;
# on rewalk dessus pour transformer les adresses en IDs
for aid in addrIds:
cur_hash_rev = string.replace(cur_hash_rev, aid[0], aid[1])
# return cur_hash
# print "hash:"
# print cur_hash_rev
m2 = _hashlib.new("md5")
m2.update(cur_hash_rev)
iHash = m2.hexdigest()[-8:]
return iHash
def get_online(*args):
global backup_file, m7, poli_id, sample_id, skel_conn
if skel_conn.is_online:
return 0
print ""
print "<!------- POLICHOMBR UPDATE -------!>"
skel_conn.get_online()
SaveBase(backup_file, idaapi.DBFL_TEMP)
# test si le sample courant existe sur poli et si non, on le cree :]
if poli_id == 0:
data = skel_conn.poli_get(
"/api/1.0/samples/" +
lower(
GetInputMD5()) +
"/")
if data["sample_id"] is not None:
sample_id = data["sample_id"]
else:
print "[!] Cannot find remote sample"
# XXX upload sample!
skel_conn.get_offline()
return 0
# maintenant on peut update (et pousser nos modifs au passage)
if update_poli_db() == -1:
return -1
# remove les liens vu qu'on en a plus besoin
if "m7" in globals() and m7 is not None:
idaapi.del_menu_item(m7)
m7 = None
# if "m8" in globals() and m8 != None:
# idaapi.del_menu_item(m8)
#m8 = None
print "[+] Update finished"
print "<!---------------------------------!>"
return 0
def update_poli_db():
pass
def end_skelenox():
"""
cleanup
"""
global sample_id, skel_conn
# cut connection
skel_conn.close_connection()
# on enleve les hooks
cleanup_hooks()
print "[!] Skelenox terminated"
# et on reset les globales importantes
sample_id = 0
return
def init_skelenox():
global crit_backup_file, backup_file, last_saved
global last_timestamp
global sample_id
global m7, polihook, skellhook, skelhook_set, notepadHandle
global skelV
global is_updating
global skel_conn
global skel_settings, settings_filename
is_updating = 0
notepadHandle = None
skelhook_set = False
last_timestamp = -1
sample_id = 0
poli_id = 0
last_saved = 0
print "[+] Init Skelenox"
# Load settings
skel_settings = SkelConfig(settings_filename)
skel_conn = SkelConnection(skel_settings.poli_server,
skel_settings.poli_port,
skel_settings.poli_remote_path,
skel_settings.poli_apikey,
skel_settings.debug_http)
cleanup_hooks()
# GetIdbPath() c'est un peu violent comme filename, changer si besoin
crit_backup_file = GetIdbPath()[:-4] + "_backup_preskel_.idb"
backup_file = GetIdbPath()[:-4] + "_backup_.idb"
atexit.register(end_skelenox)
print "[+] Backuping IDB (_backup_preskel_)"
SaveBase(crit_backup_file, idaapi.DBFL_TEMP)
print "[+] Backuping IDB (_backup_)"
SaveBase(backup_file, idaapi.DBFL_TEMP)
last_saved = time.time()
# online, avec overwrite
# => si on load au startup, tout est deja commit donc pas de diff
# => sinon on ajoute les 2 boutons qui vont bien
if skel_settings.online_at_startup is None:
choice = idaapi.askbuttons_c("Yes",
"No",
"Cancel",
0,
"Do you want to start Polichombr synchro?")
if choice == 1:
skel_settings.online_at_startup = True
else:
skel_settings.online_at_startup = False
# on passe online et on verifie qu'il n'y a pas eu d'update
if skel_settings.online_at_startup:
if get_online() == -1:
return
# synchro du sample
if startup() == -1:
return
# setup hooks
polihook = MyUiHook()
polihook.hook()
if not skel_settings.online_at_startup:
m7 = idaapi.add_menu_item(
"View/",
"Poli: Poli synchro",
"",
0,
get_online,
None)
print "[+] Skelenox init finished"
_help()
return
def shex(a):
"""
custom, pour supprimer les L finaux, au cas ou
"""
return hex(a).rstrip("L")
def shexst(a):
return hex(a).rstrip("L").lstrip("0x") or 0
def CheckDefaultValue(name):
default_values = ['sub_', "dword_", "unk_", "byte_", "word_", "loc_"]
for value in default_values:
if value in name[:6]:
return 1
return 0
def hasSubNoppedPrefix(name):
if name is not None and name[:4] != "sub_" and name[:1] != "?" and name[
:7] != "nullsub" and name[:7] != "unknown" and name[0] != "_" and name[0] != "@":
return False
return True
# TODO : les SetFuntionCmt ne passe pas: y'a 3 parametres...
# En pratique, personne ne l'a jamais used
def push_comms():
global skel_conn
commBL = [
"size_t", "int", "LPSTR", "char", "char *", "lpString", "unsigned int", "void *",
"indirect table for switch statement", "this", "jump table for switch statement", "switch jump"]
for i in range(idc.MinEA(), idc.MaxEA()):
if idc.GetCommentEx(
i, 0) is not None and not idc.GetCommentEx(i, 0) in commBL:
if not skel_conn.push_comment(i, idc.GetCommentEx(i, 0)):
return -1
elif idc.GetCommentEx(i, 1) is not None and not idc.GetCommentEx(i, 1) in commBL:
if not skel_conn.push_comment(i, idc.GetCommentEx(i, 1)):
return -1
for function_ea in idautils.Functions(idc.MinEA(), idc.MaxEA()):
fName = idc.GetFunctionName(function_ea)
if hasSubNoppedPrefix(fName) == False:
if pushchange("idc.MakeName", shex(function_ea), fName) == -1:
return -1
# if idc.GetFunctionCmt(function_ea,0) != "":
# pushchange("idc.SetFunctionCmt",shex(function_ea),idc.GetFunctionCmt(i,0))
# elif idc.GetFunctionCmt(function_ea,1) != "":
# pushchange("idc.SetFunctionCmt",shex(function_ea),idc.GetFunctionCmt(function_ea,1))
return 0
class MyUiHook(idaapi.UI_Hooks):
"""
Catch IDA actions and send them
"""
cmdname = ""
addr = 0
def __init__(self):
idaapi.UI_Hooks.__init__(self)
def preprocess(self, name):
# checkupdates()
self.cmdname = name
self.addr = idc.here()
return 0
def term(self):
end_skelenox()
def postprocess(self):
global skel_conn
try:
if self.cmdname == "MakeComment":
if idc.GetCommentEx(self.addr, 0) is not None:
skel_conn.push_comment(
self.addr, idc.GetCommentEx(
(self.addr), 0))
elif idc.GetCommentEx(self.addr, 1) is not None:
skel_conn.push_comment(
self.addr, idc.GetCommentEx(
(self.addr), 1))
elif idc.GetFunctionCmt(self.addr, 0) != "":
skel_conn.push_comment(
self.addr, idc.GetCommentEx(
(self.addr), 0))
elif idc.GetFunctionCmt(self.addr, 1) != "":
skel_conn.push_comment(self.addr, idc.GetFunctionCmt(
self.addr, 1).replace("\n", "\\n").replace("\"", "\\\""))
if self.cmdname == "MakeRptCmt":
if idc.GetCommentEx(self.addr, 0) is not None:
skel_conn.push_comment(self.addr, idc.GetCommentEx(
self.addr, 0).replace("\n", "\\n").replace("\"", "\\\""))
elif idc.GetCommentEx(self.addr, 1) is not None:
skel_conn.push_comment(self.addr, idc.GetCommentEx(
self.addr, 1).replace("\n", "\\n").replace("\"", "\\\""))
elif idc.GetFunctionCmt(self.addr, 0) != "":
skel_conn.push_comment(self.addr, idc.GetFunctionCmt(
self.addr, 0).replace("\n", "\\n").replace("\"", "\\\""))
elif idc.GetFunctionCmt(self.addr, 1) != "":
skel_conn.push_comment(self.addr, idc.GetFunctionCmt(
self.addr, 1).replace("\n", "\\n").replace("\"", "\\\""))
elif self.cmdname == "MakeName":
# idc.Jump(self.addr)
if (idc.GetFunctionAttr(self.addr, 0) == self.addr):
fname = GetFunctionName(self.addr)
if fname != "":
if CheckDefaultValue(fname) != 1:
skel_conn.push_name(self.addr, fname)
else:
fname = idc.GetTrueName(self.addr)
if fname != "" and CheckDefaultValue(fname) == 0:
skel_conn.push_name(self.addr, fname.replace(
"\n", "\\n").replace("\"", "\\\""))
else:
# ok, on regarde ce qui est pointe
if GetOpType(self.addr, 0) in [o_near, o_imm, o_mem]:
if GetOpType(self.addr, 1) in [
o_near, o_imm, o_mem]:
print "[P] You must be on the top of function or at the global address to set the name in log file"
else:
add = idc.GetOperandValue(self.addr, 0)
fname = idc.GetTrueName(add)
if fname != "" and CheckDefaultValue(
fname) == 0:
skel_conn.push_name(add, fname.replace(
"\n", "\\n").replace("\"", "\\\""))
else:
print "[P] You must be on the top of function or at the global address to set the name in log file"
elif GetOpType(self.addr, 1) in [o_near, o_imm, o_mem]:
add = idc.GetOperandValue(self.addr, 1)
fname = idc.GetTrueName(add)
if fname != "" and CheckDefaultValue(fname) == 0:
skel_conn.push_name(add, fname.replace(
"\n", "\\n").replace("\"", "\\\""))
else:
print "[P] You must be on the top of function or at the global address to set the name in log file"
elif self.cmdname == "MakeFunction":
if idc.GetFunctionAttr(self.addr, 0) is not None:
pushchange("idc.MakeFunction", shex(idc.GetFunctionAttr(
self.addr, 0)), shex(idc.GetFunctionAttr(self.addr, 4)))
elif self.cmdname == "DeclareStructVar":
print "Fixme : declare Struct variable"
elif self.cmdname == "AddStruct":
print "Fixme : adding structure"
elif self.cmdname == "SetType":
newtype = idc.GetType(self.addr)
if newtype is None:
newtype = ""
else:
newtype = prepare_parse_type(newtype, self.addr)
pushchange("idc.SetType", shex(self.addr), newtype)
elif self.cmdname == "OpStructOffset":
print "Fixme, used when typing a struct member/stack var/data pointer to a struct offset "
except KeyError:
pass
return 0
def prepare_parse_type(typestr, ea):
"""
idc.ParseType doesnt accept types without func / local name
as exported by default GetType
this is an ugly hack to fix it
FIXME : parsing usercall (@<XXX>)
"""
lname = idc.GetTrueName(ea)
if lname is None:
lname = "Default"
# func pointers
fpconventions = ["__cdecl *",
"__stdcall *",
"__fastcall *",
#"__usercall *",
#"__userpurge *",
"__thiscall *"]
cconventions = ["__cdecl",
"__stdcall",
"__fastcall",
#"__usercall",
#"__userpurge",
"__thiscall"]
flag = False
for conv in fpconventions:
if conv in typestr:
mtype = typestr.replace(conv, conv + lname)
flag = True
if not flag:
# replace prototype
for conv in cconventions:
if conv in typestr:
mtype = typestr.replace(conv, conv + " " + lname)
flag = True
return mtype
def compare_s(*args):
"""
wrapper sur idc.here()
"""
print ""
print "<!------- SUB HASH COMPARE -------!>"
print "[+] Searching for " + GetFunctionName(idc.here())
print compare_sub(idc.here())
print "<!--------------------------------!>"
return
def compare_sub(addr):
pass
def find_hash(*args):
# read le hash
needle = idaapi.askstr(0, "ERROR", "Hash value")
if needle is None or needle == "ERROR" or len(needle) > 8:
idaapi.warning("Bad input, please specify a 8 bytes hash")
return
fHash(needle)
return
def fHash(needle):
# TODO : query poli for a machoc
pass
class hookEr(idaapi.IDP_Hooks):
"""
# hook IDP
# analyse de fonction des changement du ptr
# save l'IDB / update la poliDB toutes les 10 minutes
"""
curfuncstart = 0
curfuncend = 0
def __init__(self):
idaapi.IDP_Hooks.__init__(self)
def custom_out(self):
global last_saved, backup_file, skel_settings
if last_saved < (time.time() - skel_settings.save_timeout):
print "[+] Saving IDB"
SaveBase(backup_file, idaapi.DBFL_TEMP)
print "[+] Updating database"
update_poli_db()
last_saved = time.time()
addr = idc.here()
if addr < self.curfuncstart or addr > self.curfuncend:
ea = ScreenEA()
if idaapi.get_func(ea) is not None:
cfs = idaapi.get_func(ea).startEA
cfe = idaapi.get_func(ea).endEA
if cfe == BADADDR:
cfe = idaapi.get_func(self.curfuncS).endEA
if cfe != BADADDR and cfs != BADADDR:
self.curfuncstart = cfs
self.curfuncend = cfe
print analyzeFunction(addr)[0]
return idaapi.IDP_Hooks.custom_out(self)
def rename(self, *args):
print "RENAMING"
return super(self, IDP_Hook).rename()
def cleanup_hooks():
"""Clean IDA hooks on exit"""
global uihook, polihook, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10
if "polihook" in globals() and polihook is not None:
polihook.unhook()
polihook = None
if "uihook" in globals() and uihook is not None:
uihook.unhook()
uihook = None
if "m1" in globals() and m1 is not None:
idaapi.del_menu_item(m1)
m1 = None
if "m2" in globals() and m2 is not None:
idaapi.del_menu_item(m2)
m2 = None
if "m3" in globals() and m3 is not None:
idaapi.del_menu_item(m3)
m3 = None
if "m4" in globals() and m4 is not None:
idaapi.del_menu_item(m4)
m4 = None
if "m5" in globals() and m5 is not None:
idaapi.del_menu_item(m5)
m5 = None
if "m6" in globals() and m6 is not None:
idaapi.del_menu_item(m6)
m6 = None
if "m7" in globals() and m7 is not None:
idaapi.del_menu_item(m7)
m7 = None
if "m8" in globals() and m8 is not None:
idaapi.del_menu_item(m8)
m8 = None
if "m9" in globals() and m9 is not None:
idaapi.del_menu_item(m9)
m9 = None
if "m10" in globals() and m10 is not None:
idaapi.del_menu_item(m10)
m10 = None
return
def _help():
"""
help!
"""
print "------------------------------------------------------------------------------------------------"
print " SKELENOX "
print "------------------------------------------------------------------------------------------------"
print "Help:"
print "Commands in View/Poli:*** items:"
print "- Compare: Compare current function with polichombr subs DB"
print "- Poli notepad : polichombr notepad"
print "- Poli synchro : polichombr synchro (if you're offline)"
print "- Tracker: set/unset dynamic sub tracker"
print "- Find hash: walks through subs to find a sub hash"
print "------------------------------------------------------------------------------------------------"
print "\tfile %IDB%_backup_preskel_ contains pre-critical ops IDB backup"
print "\tfile %IDB%_backup_ contains periodic IDB backups"
return
def tracker(*args):
"""
Init le tracker
"""
global skelhook, skelhook_set
if skelhook_set:
print "[+] UI hook uninstall"
skelhook.unhook()
del skelhook
skelhook = None
skelhook_set = False
else:
print "[+] UI hook install"
skelhook = hookEr()
skelhook.hook()
skelhook_set = True
return
if __name__ == '__main__':
# RUN !
init_skelenox()