-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.ml
799 lines (768 loc) · 28.1 KB
/
main.ml
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
(* Assumes the parser file is parser.mly and the lexer file is "lexer.mll". *)
open Common
open Printf
open Ast (* for types *)
open Cdefs
open Analysis
let hARDCODED_PRINTF = 0x080484a0
let cRASH_ADDRESS = 0x1111
let sTACK_VAR_OFF = 0
let fRAME_VAR_OFF = 4
let dATA_OFF = 8 (* start writing tables here *)
let nO_NAME_LABEL = "@@"
let gLOBAL_END_LABEL = "global_end"
let trd (_,_,x) = x
let i32 = Int32.of_int
let fun_label id = "function_"^id
let fun_local_label fun_id id = "local_"^fun_id^"_"^id
let print_errors errors =
let errors = Ast.dump_errors errors in
let rec aux errors =
match errors with
| hd::tl ->
let hd = "ERROR. "^hd^"\n" in
let _ = printf "%s" hd in
aux tl
| [] -> ()
in
aux errors
let pick_different_reg used =
let regs = Common.rEGS_NO_ESP in
let p reg = try let _ = List.find (fun x->x=reg) used in false with Not_found -> true in
let not_used = List.filter p regs in
match not_used with
| hd::tl -> hd
| _ -> assert false
(* every invocation of f_next_reg returns new symbolic reg *)
let make_rewrite_exp f_next_reg read_local ref_local =
let rec rewrite_exp exp oreg =
match exp with
| BinOp(exp1, op, exp2) ->
let reg1 = f_next_reg () in
let iexp1 = rewrite_exp exp1 reg1 in
let reg2 = f_next_reg () in
let iexp2 = rewrite_exp exp2 reg2 in
let o = BinO(oreg, reg1, op, reg2) in
iexp1 @ iexp2 @ [o]
| UnOp(op, exp) ->
begin
match op with
| Sub -> rewrite_exp (BinOp(Const(0),op,exp)) oreg
| Not -> rewrite_exp (BinOp(Const(-1),Xor,exp)) oreg
| _ -> assert false
end
| Var(id) ->
let rl = read_local id oreg in
[rl]
| Ref(id) ->
let rl = ref_local id oreg in
[rl]
| ReadMem(id) ->
let addr_reg = f_next_reg () in
let rl = read_local id addr_reg in
let rm = ReadM(oreg, addr_reg) in
[rl;rm]
| Const(x) ->
let mov = MovRegConst(oreg, x) in
[mov]
in
rewrite_exp
let rewrite_stmt stack_ptr frame_ptr locals fun_id stmt =
let f_next_reg = make_reg_generator () in
let rw_local id reg f_ctor =
let id2off id = try Hashtbl.find locals id with Not_found -> assert false in
let off = id2off id in
f_ctor off reg
in
let write_local id reg =
rw_local id reg (fun off reg -> WriteLocal(off,reg))
in
let read_local id reg =
rw_local id reg (fun off reg -> ReadLocal(off,reg))
in
let ref_local id reg =
rw_local id reg (fun off reg -> LocalAddr(off, reg))
in
let deref_local id reg =
let f off reg =
let addr_reg = f_next_reg () in
let rl = ReadLocal(off, addr_reg) in
let wm = WriteM(addr_reg, reg) in
[rl;wm]
in
rw_local id reg f
in
let rewrite_exp = make_rewrite_exp f_next_reg read_local ref_local in
let push_arg arg =
(* just check if args are simple *)
let _ = match arg with
| Var(_) | ReadMem(_) | Ref(_) | Const(_) -> true
| _ -> assert false
in
let reg = f_next_reg () in
let iarg = rewrite_exp arg reg in
let push = PushReg(reg) in
iarg @ [push]
in
let push_args args =
let rec aux acc args =
match args with
| arg::tl ->
let pa = push_arg arg in
aux (pa::acc) tl
| [] -> acc
in
let pushes = aux [] args in
(* let pushes = List.rev pushes in *)
List.concat pushes
in
let set_eax_on_cond cond =
(* ah = SF ZF xx AF xx PF xx CF *)
(* returns mask and the value required to take the jump *)
let flag_mask_const flag =
let mask,v =
match flag with
| E -> (1 lsl 6), 1 lsl 6 (* jz, ZF = 1 *)
| A -> (1 lor (1 lsl 6)), 0 (* ja, CF = ZF = 0 *)
| B -> 1, 1 (* jb, CF = 1 *)
| _ -> assert false
in
(* flags are saved to AH, so shift *)
let mask,v = mask lsl 8, v lsl 8 in
mask, v
in
let neg, flags =
match cond with
| Cond(flags) -> false, flags
| NCond(flags) -> true, flags
in
(* FIXME: just one flag atm *)
let flag = match flags with hd::[] -> hd | _ -> assert false in
if flag=MP then
let mov = MovRegConst(C(EAX), 1) in
[mov]
else
let mask, v = flag_mask_const flag in
let reg = f_next_reg () in
let mov1 = MovRegConst(reg, mask) in
let and_ah = BinO(C(EAX), C(EAX), And, reg) in
let reg = f_next_reg () in
let mov2 = MovRegConst(reg, v) in
let sub = BinO(C(EAX), C(EAX), Sub, reg) in
let lahf = SaveFlags in
let reg = f_next_reg () in
(* ZF position in EAX: 6th bit of AH *)
let mov3 = MovRegConst(reg, 1 lsl (6+8)) in
let shr = BinO(C(EAX), C(EAX), Div, reg) in
let reg = f_next_reg () in
let mov4 = MovRegConst(reg, 1) in
(* eax=1 iff cond *)
let last = [BinO(C(EAX), C(EAX), And, reg)] in
let last = last @
if neg then [BinO(C(EAX), C(EAX), Xor, reg)]
else []
in
[mov1;and_ah;mov2;sub;lahf;mov3;shr;mov4]@last
in
let rewrite stmt =
match stmt with
| Assign(id, exp) ->
let reg = f_next_reg () in
let iexp = rewrite_exp exp reg in
let wl = write_local id reg in
iexp @ [wl]
| DerefAssign(id, exp) ->
let reg = f_next_reg () in
let iexp = rewrite_exp exp reg in
let wl = deref_local id reg in
iexp @ wl
| WriteMem(id, exp) ->
let exp_reg = f_next_reg () in
let iexp = rewrite_exp exp exp_reg in
let addr_reg = f_next_reg () in
let rl = read_local id addr_reg in
let wm = WriteM(addr_reg, exp_reg) in
iexp @ [rl;wm]
| Cmp(exp1, exp2) ->
let reg1, reg2 = f_next_reg (), f_next_reg () in
let iexp1 = rewrite_exp exp1 reg1 in
let iexp2 = rewrite_exp exp2 reg2 in
let reg = f_next_reg () in
let sub = BinO(reg, reg1, Sub, reg2) in
let lahf = SaveFlags in
iexp1 @ iexp2 @ [sub; lahf]
| Call(id, ExpArgs(exp_args)) ->
let pushes = push_args exp_args in
let reg = f_next_reg () in
let mov = MovRegSymb(reg, FromTo(Named(fun_label id), Unnamed(Forward))) in
let p = PushReg(reg) in
let reg = f_next_reg () in
let mov2 = MovRegSymb(reg, FromTo(Unnamed(Forward), Named(fun_label id))) in
let add = OpStack(Add, reg) in (* jmp *)
let lbl = Lbl(nO_NAME_LABEL) in
pushes @ [mov;p;mov2;add;lbl]
| ExtCall(id, ExpArgs(exp_args)) ->
let rec range i j = if i >= j then [] else i :: (range (i+1) j) in
let make_filler n =
let m x = let x = x land 0xFF in (x lsl 24) lor (x lsl 16) lor (x lsl 8) lor x in
let f acc x = RawHex(m x)::acc in
let nums = range 0 n in
let filler = List.fold_left f [] nums in
let filler = List.rev filler in
filler
in
let store_args imp_addr args =
let addr_reg = f_next_reg () in
let v_reg = f_next_reg () in
let off_reg = f_next_reg () in
let fix_reg = f_next_reg () in
let per_arg acc arg =
let iarg = rewrite_exp arg v_reg in
let wm = WriteM(addr_reg, v_reg) in
let set = MovRegConst(off_reg, 4) in
let add = BinO(addr_reg, addr_reg, Add, off_reg) in
acc @ (iarg@[wm;set;add]) (* O(n^2) *)
in
let tmp_reg = f_next_reg () in
let lbl = Lbl(nO_NAME_LABEL) in
let save_esp = MovRegReg(tmp_reg, C(ESP)) in
let mov = MovRegSymb(fix_reg, FromTo(Unnamed(Backward), Unnamed(Forward))) in
let fix1 = BinO(addr_reg, tmp_reg, Add, fix_reg) in
(* Restore import address *)
let reg = f_next_reg () in
let set_imp = MovRegConst(reg, imp_addr) in
let wm = WriteM(addr_reg, reg) in
let reg = f_next_reg () in
let set8 = MovRegConst(reg, 8) in
let fix2 = BinO(addr_reg, addr_reg, Add, reg) in
let stores = List.fold_left per_arg [] args in
[save_esp;lbl;mov;fix1;set_imp;wm;set8;fix2] @ stores
in
let jmp_over_locals locals_filler =
let n = List.length locals_filler in
let reg = f_next_reg () in
let mov = MovRegConst(reg, n*4) in
let ops = OpStack(Add, reg) in
[mov;ops]
in
let imp_addr = hARDCODED_PRINTF in
let cmt_s = sprintf "jmp %s" id in
(* At least 128 bytes for locals *)
let n_args = List.length exp_args in
let locals_filler = make_filler (256/4) in
let jmp_skip_locals = jmp_over_locals locals_filler in
(* FIXME: hardcoded printf *)
let jmp_imp = RawHex(imp_addr) in
(* FIXME: we don't need equality in AdvStack, just >= *)
let adv = AdvanceStack(n_args*4+4) in
let lbl = Lbl(nO_NAME_LABEL) in
let args_filler = make_filler n_args in
let write_args = store_args imp_addr exp_args in
write_args @ jmp_skip_locals @ locals_filler @
[Comment(cmt_s);lbl;jmp_imp;adv] @ (args_filler)
| Branch(cond, id) ->
(* eax=1 iff cond, 0 otherwise *)
let setz = set_eax_on_cond cond in
let reg = f_next_reg () in
let start = Unnamed(Forward) in
let fin = Named(fun_local_label fun_id id) in
let mov = MovRegSymb(reg, FromTo(start, fin)) in
let mul = BinO(C(EAX), C(EAX), Mul, reg) in
let add = OpStack(Add, C(EAX)) in (* jmp *)
let lbl = Lbl(nO_NAME_LABEL) in
setz @ [mov; mul; add; lbl;]
| Label(id) -> [Lbl(fun_local_label fun_id id)]
| Enter(n) ->
let reg = f_next_reg () in
let rm1 = ReadMConst(reg, frame_ptr) in
let push = PushReg(reg) in
let reg = f_next_reg () in
let rm2 = ReadMConst(reg, stack_ptr) in
let wm1 = WriteMConst(frame_ptr, reg) in
let reg1 = f_next_reg () in
let rm3 = ReadMConst(reg1, stack_ptr) in
let reg2 = f_next_reg () in
let mov = MovRegConst(reg2, n) in
let reg3 = f_next_reg () in
let sub = BinO(reg3, reg1, Sub, reg2) in
let wm2 = WriteMConst(stack_ptr, reg3) in
[rm1;push;rm2;wm1;rm3;mov;sub;wm2]
| Leave ->
let reg = f_next_reg () in
let rm = ReadMConst(reg, frame_ptr) in
let wm1 = WriteMConst(stack_ptr, reg) in
let reg = f_next_reg () in
let pop = PopReg(reg) in
let wm2 = WriteMConst(frame_ptr, reg) in
[rm;wm1;pop;wm2]
| Ret(id) ->
let reg1 = f_next_reg () in
let reg2 = f_next_reg () in
let reg3 = f_next_reg () in
let p2 = PopReg(reg1) in
let mov = MovRegSymb(reg2, FromTo(Unnamed(Forward), Named(fun_label id))) in
let sub = BinO(reg3, reg2, Add, reg1) in
let add = OpStack(Add, reg3) in (* jmp *)
let lbl = Lbl(nO_NAME_LABEL) in
[p2;mov;sub;add;lbl;]
(* AssignTab is replaced with Assign(id,C) earlier *)
| AssignTab(_,_) -> assert false
in
let new_instrs = rewrite stmt in
let comments =
match stmt with
| Label(_) -> []
| _ ->
let s = Ast.dump_stmt stmt in
[Comment(s)]
in
comments @ new_instrs
let rewrite_prog prog stack_ptr frame_ptr =
let assign_vars func =
let collect_locals stmts =
let rec aux acc stmts =
match stmts with
(* all locals are initialized before use *)
| (Assign(id,_))::tl -> aux (id::acc) tl
| hd::tl -> aux acc tl
| [] -> acc
in
let ids = aux [] stmts in
let ids = Common.generic_unique ids in
ids
in
let Fun(id, Args(args), FunBody(stmts)) = func in
let h = Hashtbl.create 32 in
let f (h,n) arg =
let _ = Hashtbl.add h arg n in
(h,n+4)
in
(* v1,frame,ret,arg1,...,argN *)
let (h,_) = List.fold_left f (h,12) args in
let g (h,n) id =
let _ = Hashtbl.add h id n in
(h,n-4)
in
let ids = collect_locals stmts in
let (h,_) = List.fold_left g (h,0) ids in
h
in
let rewrite_func func =
let add_stack_stuff fun_id locals stmts =
let locals_count = Hashtbl.length locals in
(* every local is a dword *)
let pre = [Enter(locals_count*4)] in
let suf = [Leave;Ret(fun_id)] in
let stmts = pre@stmts@suf in
stmts
in
let rewrite_stmt = rewrite_stmt stack_ptr frame_ptr in
let Fun(fun_id, Args(args), FunBody(stmts)) = func in
let locals = assign_vars func in
let stmts = add_stack_stuff fun_id locals stmts in
let instrs = List.map (fun stmt -> rewrite_stmt locals fun_id stmt) stmts in
let head = Ast.dump_func_head func in
let fun_lbl = fun_label fun_id in
let pre = [Comment(head); Lbl(fun_lbl);] in
let instrs = [pre]@instrs in
instrs
in
let Prog(func_list) = prog in
let rew = List.map rewrite_func func_list in
(* let rew = List.concat (rew) in *)
rew
(* Extract tables and create a stub that writes them to the data section.
* All AssignTable(id,list) are changed to Assign(id,C), where C is the
* address in .data section *)
let handle_tables data_s prog =
let per_func data_start func =
let h = Hashtbl.create 8 in
let per_stmt acc stmt =
let (off, pairs, rew) = acc in
match stmt with
| AssignTab(id, l) ->
let new_stmt = Assign(id, Const(off)) in
let new_off = off + List.length l in
new_off,(off,l)::pairs,new_stmt::rew
| _ -> off,pairs,stmt::rew
in
let Fun(fun_id, Args(args), FunBody(stmts)) = func in
let data_end, pairs, stmts = List.fold_left per_stmt (data_start,[],[]) stmts in
let stmts = List.rev stmts in
let func = Fun(fun_id, Args(args), FunBody(stmts)) in
data_end, pairs, func
in
let per_func_fold (data_start,l_pairs,funs) func =
let data_end, f_pairs, new_func = per_func data_start func in
(data_end, f_pairs::l_pairs, new_func::funs)
in
let dump_pairs pairs =
let pr (off, l) =
let s = dump_int_list l in
printf "0x%08x,%s\n" off s
in
List.map pr pairs
in
let make_stub pairs =
let store addr v =
let r = S(-1) in
let mov = MovRegConst(r, v) in
let wm = WriteMConst(addr, r) in
[mov;wm]
in
let chop l n =
let f (i,a,b) x = if i<n then (i+1,x::a,b) else (i+1,a,x::b) in
let (_,a,b) = List.fold_left f (0,[],[]) l in
List.rev a, List.rev b
in
let to_int l =
let f acc x = (acc lsl 8)+x in
List.fold_left f 0 l
in
let make_one off l =
let rec aux acc off l =
let pre,suf = chop l 3 in
match pre with
| hd::tl ->
let v = to_int (List.rev pre) in
let s = store off v in
aux (s::acc) (off+3) suf
| [] -> List.flatten (List.rev acc)
in
let s = aux [] off l in
s
in
let f acc (off,l) =
let s = make_one off l in
s::acc
in
let ss = List.fold_left f [] pairs in
List.flatten (List.rev ss)
in
let data_start = data_s+dATA_OFF in
let Prog(func_list) = prog in
let (_,l_pairs,funs) = List.fold_left per_func_fold (data_start,[],[]) func_list in
let funs = List.rev funs in
let pairs = List.rev (List.flatten l_pairs) in
let _ = dump_pairs pairs in
let new_prog = Prog(funs) in
let stub = make_stub pairs in
stub, new_prog
let add_comments f_comment new_instrs prefix instr =
let comments =
if f_comment instr then
let s = dump_instr instr in
[Comment(prefix^s)]
else
[]
in
comments @ new_instrs
(* concretize symbolic constants *)
(* IN: (instr,gm) pairs
* OUT: (instr,gm) pairs without MovRegSymb *)
let fix_symblic pairs =
let get_size gm =
let GMeta(_,_,_,stack_fix) = gm in
stack_fix
in
let check_lbl label instr = match instr with Lbl(lab) -> label=lab | _ -> false in
let distance_to_generic f_match pairs =
let rec aux dist pairs =
match pairs with
| (instr,gm)::tl ->
if f_match instr then
(*
let _ = Printf.printf "found label %s in: %s\n" label
(dump_instr instr) in
*)
Some(dist)
else
begin
(* Ignore gmetas for labels and comments -_-' *)
if is_lbl_or_comment instr then
aux dist tl
else
let size = get_size gm in
aux (size+dist) tl
end
| [] -> None
in
let dist = aux 0 pairs in
dist
in
let distance_to_lbl lbl pairs =
let f_match = check_lbl lbl in
let dist = distance_to_generic f_match pairs in
dist
in
let try_both_ways id pre suf =
let before = distance_to_lbl id pre in
let after = distance_to_lbl id suf in
match before,after with
| Some(_),Some(_) -> failwith ("Found duplicate: "^id)
| None, None -> failwith ("Can't find label:"^id)
| Some(n),None -> -n
| None,Some(n) -> n
in
let distance_to_unnamed dir pre suf =
let sign,chunk =
match dir with
| Forward -> 1,suf
| Backward -> -1,pre
in
let dist = distance_to_lbl nO_NAME_LABEL chunk in
match dist with
| Some(n) -> sign*n
| None -> failwith "Unnamed not found"
in
let get_distance symb pre suf =
match symb with
| Named(id) -> try_both_ways id pre suf
| Unnamed(dir) -> distance_to_unnamed dir pre suf
in
let rec aux pre suf =
match suf with
| (MovRegSymb(reg, FromTo(start, fin)),gm)::tl->
let dstart = get_distance start pre suf in
let dfin = get_distance fin pre suf in
let dist = dfin-dstart in
let _ = printf "FromTo: (%s,%s)->(%d,%d)->%d\n" (dump_symb start) (dump_symb fin) dstart dfin dist in
let fix = MovRegConst(reg, dist) in
aux ((fix,gm)::pre) tl
| hd::tl -> aux (hd::pre) tl
| [] -> List.rev pre
in
aux [] pairs
(* AdvanceStack -> RawHex.
* to_binary would try to fill the gap before the return address,
* but we use that space for arguments. *)
let fix_ext_call_stuff pairs =
let get_addr gm =
let GMeta(_, fm, _, _) = gm in
let FileMeta(off_s, _) = fm in
off_s
in
let set_stack_fix gm sf =
let GMeta(g,fm,mod_reg,_) = gm in
GMeta(g,fm,mod_reg,sf)
in
let f acc (instr,gmeta) =
let new_instr =
match instr with
| AdvanceStack(n) -> RawHex(get_addr gmeta)
| _ -> instr
in
if new_instr <> instr then
let cmt = Comment(dump_instr instr) in
let fake_gm = set_stack_fix gmeta 4 in
let p1 = (new_instr, fake_gm) in
let p2 = (cmt, gmeta) in
p1::p2::acc
else (instr,gmeta)::acc
in
let pairs = List.fold_left f [] pairs in
List.rev pairs
let write_const_const src_reg addr_reg addr value =
let m1 = MovRegConst(src_reg, value) in
let m2 = MovRegConst(addr_reg, addr) in
let wm1 = WriteM(addr_reg, src_reg) in
[m1; m2; wm1]
let global_prefix_suffix data_s data_e =
let stack_top = data_e in
let stack_frame = stack_top in
let st_ptr = data_s+sTACK_VAR_OFF in (* global var holding stack_top *)
let sf_ptr = data_s+fRAME_VAR_OFF in (* -- stack_frame *)
let addr_reg, src_reg = S(-1), S(-2) in (* HACK *)
let write_st = write_const_const src_reg addr_reg st_ptr stack_top in
let write_sf = write_const_const src_reg addr_reg sf_ptr stack_frame in
let reg = S(-3) in
let mov = MovRegSymb(reg, FromTo(Named(fun_label "main"), Named(gLOBAL_END_LABEL))) in
let push = PushReg(reg) in
let lbl = Lbl(gLOBAL_END_LABEL) in
let pre = write_st @ write_sf @ [mov; push] in
let suf = [lbl] in
pre, suf, st_ptr, sf_ptr
let to_binary_one io (instr,gm) =
let get_lc_off g =
match g with
| LoadConst(_,off) -> off
| _ -> assert false
in
let fill io n =
let dwords = n / 4 in
let bytes = n mod 4 in
let rec aux i f m =
if i < m then
let _ = f n io in aux (i+1) f m
else ()
in
let f_d n io = IO.write_i32 io n in
let f_b n io = IO.write_byte io n in
let _ = aux 0 f_d dwords in
let _ = aux dwords f_b (dwords+bytes) in
()
in
let value_to_write instr off_s =
match instr with
| RawHex(v) -> v
| _ -> off_s
in
let GMeta(g, fm, _, stack_fix) = gm in
let FileMeta(off_s, _) = fm in
let v = value_to_write instr off_s in
let _ = IO.write_i32 io v in
let _ =
match instr with
| MovRegConst(r,v) ->
let off = get_lc_off g in
let _ = assert (stack_fix - off - 4 >= 0) in
let _ = fill io off in
let _ = IO.write_i32 io v in
fill io (stack_fix - off - 8)
| RawHex(_) -> assert (stack_fix = 4)
| _ -> fill io (stack_fix-4)
in
(* return string *)
()
let filter_trash pairs =
let p (i,_) =
match i with
| Lbl(_) | Comment(_) -> false
| _ -> true
in
List.filter p pairs
let to_binary pairs =
let io = IO.output_string () in
let consume acc (instr,gm) =
to_binary_one io (instr,gm)
in
let _ = List.fold_left consume () pairs in
let _ = List.map (fun i -> IO.write_i32 io cRASH_ADDRESS) [1;2;3;4;5;6;7] in
IO.close_out io
let dump_possible gadgets stack_ptr frame_ptr instrs =
let implement = make_implement stack_ptr frame_ptr in
let p_by_arg, p_by_pos = make_possible_regs_funs gadgets implement in
let f _ instr =
let _ = Printf.printf "%s - " (dump_instr instr) in
let args = arg_dumper instr in
let per_arg _ arg =
let _ = Printf.printf "| %s: " (dump_sreg arg) in
let set = p_by_arg instr arg in
let regs = RegSet.elements set in
let _ = Common.generic_dumper (fun r -> Common.dump_reg r) regs in
()
in
let _ = List.fold_left per_arg () args in
Printf.printf "%s" "\n"
in
let _ = List.fold_left f () instrs in
()
(* dump 'compiled' program *)
let dump_instrs cl =
let print i =
let s = dump_instr i in
Printf.printf "%s\n" s in
let _ = List.map print cl in
()
let dump_pairs pairs =
let _ = print_endline "~~~~~~~~~~~~~" in
let pr acc (instr,gmeta) =
let GMeta(_,_,_,stack_fix) = gmeta in
let (off, sep) =
if is_lbl_or_comment instr then
acc, " "
else
acc+stack_fix, "\t"
in
let _ = printf "0x%04x%s%s\n" acc sep (dump_instr instr) in
off
in
(* First RET will add 4 *)
let _ = List.fold_left pr 4 pairs in
()
(* FIXME: main has to be at the beginning *)
let compile prog container =
let process_func assign_regs instr_lll =
let per_stmt acc instrs =
(* list of instructions, set of regs to preserve *)
let impl =
try
assign_regs instrs SRegSet.empty
with Not_found ->
let _ = dump_instrs instrs in
assert false
in
impl::acc
in
let per_func acc stmts =
let impl = List.fold_left per_stmt [] stmts in
let impl = List.rev impl in
impl::acc
in
let impl_lll = List.fold_left per_func [] instr_lll in
List.rev impl_lll
in
let verify_impl impl =
let p instr = instr_type instr = T0 in
let ok = List.for_all p impl in
if not ok then assert false
else ()
in
let GContainer(fn, (data_s, data_e), gmetas) = container in
let gadgets = get_gadgets gmetas in
let prefix, suffix, stack_ptr, frame_ptr = global_prefix_suffix data_s data_e in
(* Swap AssignTable with Assign (const).
* stub stores all tables in .data section *)
let stub, prog = handle_tables data_s prog in
(* Function to implement instructions in terms of simpler instructions.
* Ultimately instruction is converted to a list of gadgets. *)
let implement = make_implement stack_ptr frame_ptr in
let assign_regs = make_assign_regs gmetas stack_ptr frame_ptr in
(* instr list list list.
* 1st level: list of functions
* 2nd level: list of (rewritten) stmts
* 3rd level: instructions *)
let instrs_ll = rewrite_prog prog stack_ptr frame_ptr in
let instrs_ll = [stub] :: [prefix] :: instrs_ll @ [[suffix]] in
let instrs_lll = [[[Comment("lol");Lbl("1")]]] in
let instrs_lll = [[stub]] in
let impl_lll = process_func assign_regs instrs_ll in
let impl_ll = List.flatten impl_lll in
let pairs = List.flatten impl_ll in
let pairs = fix_ext_call_stuff pairs in
let instrs = List.map fst pairs in
let _ = dump_pairs pairs in
let _ = verify_impl instrs in
let pairs = fix_symblic pairs in
let pairs = filter_trash pairs in
let bin_str = to_binary pairs in
instrs, pairs, bin_str
let parse_src src_fn =
let cin = open_in src_fn in
let lexbuf = Lexing.from_channel cin in
let p = Parser.input Lexer.token lexbuf in
let errors = Ast.verify_prog p in
(p, errors)
let main () =
let argc = Array.length Sys.argv in
if argc > 2 then
let src_fn = Sys.argv.(1) in
let vg_fn = Sys.argv.(2) in
let out_fn = "compiled.bin" in
let (p, errors) = parse_src src_fn in
if errors <> [] then
print_errors errors
else
let p = Ast.unwrap_prog p in
let p = Ast.move_main_to_front p in
let p = Ast.flatten_prog p in
let container = Common.unmarshal_from_file vg_fn in
let s = Ast.dump_prog p in
let cl, pairs, bin_str = compile p container in
let _ = printf "DUMPED:\n%s\n####\n" s in
let _ = write_str_to_file out_fn bin_str in
()
else
let err = Printf.sprintf "Usage:\n%s <src fn> <vg fn>\n" Sys.argv.(0) in
print_string err
let _ = main()