-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathgdefs.ml
843 lines (761 loc) · 25.8 KB
/
gdefs.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
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
open Printf
open Symbeval
open Int_utils
open Common
let _ = Random.init 0
let oPS = [ADD; SUB; MUL; DIV; XOR; OR; AND]
let gLOBAL_MEM = "mem:?u32"
let sTACK_BASE = 0x0A1D5000
let tOO_BIG = 0x1000
let eFLAGS = "EFLAGS:u32"
let eFLAGS_MASK = 0xd5
let i32 = Int32.of_int
let (!+) = Int32.add
let (!-) = Int32.sub
let (!*) = Int32.mul
let (!/) = Int32.div
let (!^) = Int32.logxor
let (!|) = Int32.logor
let (!&) = Int32.logand
let (!<<) = Int32.shift_left
let (!>>) = Int32.shift_right
let reg_to_str reg =
match reg with
| EAX -> "EAX"
| EBX -> "EBX"
| ECX -> "ECX"
| EDX -> "EDX"
| ESI -> "ESI"
| EDI -> "EDI"
| EBP -> "EBP"
| ESP -> "ESP"
let unwrap_ast_var v =
match v with
| Ast.Var(v) -> v
| _ -> assert false
let str_to_var s =
let av,_ = Parser.exp_from_string s in
let v = unwrap_ast_var av in
v
let reg_var reg =
let reg_s = reg_to_str reg in
let reg_s = "R_"^reg_s in
let v = str_to_var reg_s in
v
let get_gadget gm =
match gm with
| GMeta(g,_,_,_) -> g
let gmeta_eq g1 g2 = get_gadget g1 = get_gadget g2
let cmp_reg r1 r2 =
let s1 = reg_to_str r1 in
let s2 = reg_to_str r2 in
String.compare s1 s2
let hash_print h dump = Hashtbl.iter (fun key data -> Printf.printf "%s\n" (dump key data)) h
let rec zip lst1 lst2 = match lst1,lst2 with
| [],_ -> []
| _, []-> []
| (x::xs),(y::ys) -> (x,y) :: (zip xs ys)
let flip pairs = List.map (fun (x,y) -> (y,x)) pairs
let modified_regs l1 l2 =
if List.length l1 <> List.length l2 then assert false else
let l = zip l1 l2 in
let f r1 r2 = if r1 <> r2 then assert false else 0 in
let _ = List.map (fun ((r1,_),(r2,_)) -> f r1 r2) l in (* catch errors *)
let l = List.filter (fun ((_,v1),(_,v2)) -> v1 <> v2) l in (* find modified *)
let l = List.map (fun ((r,_),_) -> r) l in
l
let get_mod_regs rv_pairs rv_new =
modified_regs rv_pairs rv_new
let unpack_some l =
let rec aux acc l =
match l with
| Some(x)::tl -> aux (x::acc) tl
| None::tl -> aux acc tl
| [] -> acc
in
aux [] l
(* a,e - Ast.Int() *)
let mapmem a e =
let t = Typecheck.infer_ast e in
(* XXX: Fix parser/asmir so that we don't have to do this! *)
let v, _ = Parser.exp_from_string gLOBAL_MEM in
let m = unwrap_ast_var v in
let s = Ast.Move(m, Ast.Store(v, a, e, Ast.exp_false, t), []) in
s
let mapvar name value =
let x = Parser.exp_from_string name in
let v =
match x with
| Ast.Var(v), _ -> v
| _ -> failwith "impossible: expected Var"
in
let const, _ = Parser.exp_from_string "1:u32" in
let s = Ast.Move(v, const, []) in
s
let set_var var value bits =
let v =
match bits with
| 8 -> ast_i8 value
| 16 -> ast_i16 value
| 32 -> ast_i32 value
| _ -> assert false
in
let s = Ast.Move(var, v, []) in
s
let get_var' ctx var f_cast =
let delta = ctx.delta in
let value = Symbeval.Concrete.lookup_var delta var in
let v =
match value with
| Symbolic(Ast.Int(i,t)) -> f_cast i
| Symbolic(_) -> assert false
| _ -> assert false
in
v
let get_var_int ctx var =
get_var' ctx var (Big_int.int_of_big_int)
let get_var_int32 ctx var =
let f_cast = Int_utils.i32_of_big_int in
get_var' ctx var f_cast
let set_reg reg value =
let r = reg_var reg in
let s = set_var r value 32 in
s
let get_reg' ctx reg f_get_var =
let rv = reg_var reg in
let v = f_get_var ctx rv in
v
let get_reg ctx reg = get_reg' ctx reg get_var_int
let get_reg_int32 ctx reg = get_reg' ctx reg get_var_int32
let rnd_value () = Random.bits () land 0x00FFFFFF
(* offset, value *)
let gen_dwords num_dwords =
let f i =
let d = rnd_value () in
(i*4, d)
in
let dwords = Util.mapn f num_dwords in
dwords
let fill_mem addr dwords =
(* generate instructions to fill mem starting @ addr with num_dwords values *)
let gen_stmts () =
let f acc (off, value) =
let a = ast_i32 (addr+off) in
let e = ast_i32 value in
let s = mapmem a e in
s::acc
in
let stmts = List.fold_left f [] dwords in
stmts
in
let stmts = gen_stmts () in
stmts
let gen_rv_pairs regs =
(* Is there a pair of regs r1,r2 (r1<>r2), such that eax/r1 = eax/r2 ? *)
let check_div_collision rv_pairs =
let p (r,v) = r=EAX in
let (_,eax) = try List.find p rv_pairs with Not_found -> assert false in
let rv_pairs = List.filter (fun pair -> not (p pair)) rv_pairs in
let values = List.map snd rv_pairs in
let div_values = List.map (fun v -> eax/v) values in
let div_values = Common.generic_unique div_values in
List.length values <> List.length div_values
in
let rec aux depth =
let n_regs = List.length regs in
let dwords = gen_dwords n_regs in
let dwords = List.map snd dwords in (* drop offset *)
let rv_pairs = zip regs dwords in
(* hack: make EAX bigger, so that EAX/reg is > 0 *)
let rec fix_eax acc pairs =
match pairs with
| (EAX, v)::tl -> fix_eax ((EAX, v lor 0x07000000)::acc) tl
| hd::tl -> fix_eax (hd::acc) tl
| [] -> List.rev acc
in
let rv_pairs = fix_eax [] rv_pairs in
let collision = check_div_collision rv_pairs in
if collision then
aux (depth+1)
else
rv_pairs
in
let rv_pairs = aux 0 in
rv_pairs
let make_hash pairs =
let h = Hashtbl.create (List.length pairs) in
let _ = List.map (fun (k,v) -> Hashtbl.add h k v) pairs in
h
(* input: hash, list of (reg, value)
* output: list of (reg, hash[value]) *)
let collect hash pairs =
let rec aux acc l =
match l with
| (r,v)::tl ->
let org = try Some((r, Hashtbl.find hash v)) with Not_found -> None in
aux (org::acc) tl
| [] -> acc
in
let reg_value = aux [] pairs in
unpack_some reg_value
let wrap_meta ctx gadgets mod_regs off_s off_e =
(* this can fail if esp has high bits set. reject these cases,
since they'd result in too big offsets anyway *)
let pick_stack_fix sf g =
match g with
| OpEsp(_,_,stack_fix) -> stack_fix
| _ -> sf
in
let esp =
try
get_reg ctx ESP
with Failure(_) ->
sTACK_BASE + tOO_BIG + 1
in
let stack_fix = esp - sTACK_BASE in
let sf =
match gadgets with
| OpEsp(_,_,fix)::tl -> fix
| _ -> stack_fix
in
let wm gadget =
let fm = FileMeta(off_s, off_e) in
let gm = GMeta(gadget, fm, mod_regs, sf) in
gm
in
if sf > tOO_BIG || sf < 4 then
[]
else
List.map wm gadgets
(* return all ordered pairs of l1 x l2 *)
let combos l1 l2 =
let rec aux acc l' =
match l' with
| hd::tl ->
let pairs = List.map (fun x->(hd,x)) l2 in
aux (pairs::acc) tl
| [] -> acc
in
let ll = aux [] l1 in
List.concat ll
let gen_init_and_rv_pairs' f_cast regs =
let rv_pairs = gen_rv_pairs regs in
let init = List.map (fun (r,v) -> set_reg r v) rv_pairs in
let rv_pairs = List.map (fun (r,v) -> (r, f_cast v)) rv_pairs in
(rv_pairs, init)
let gen_init_and_rv_pairs regs = gen_init_and_rv_pairs' (fun x->x) regs
let gen_init_and_rv_pairs32 regs =
let f_cast = Int32.of_int in
gen_init_and_rv_pairs' f_cast regs
let gen_init_and_rv_pairs32_no_esp () = gen_init_and_rv_pairs32 Common.rEGS_NO_ESP
let get_regs_from_ctx ctx regs =
let rv = List.map (fun r -> (r, get_reg_int32 ctx r)) regs in
rv
let get_regs_no_esp ctx = get_regs_from_ctx ctx Common.rEGS_NO_ESP
let common_init stmts =
let init_esp = set_reg ESP sTACK_BASE in
[init_esp]
(*
* procedures for gadget recognition
*)
let g_load_const () =
let num_dwords = 8 in
let dwords = gen_dwords num_dwords in
let dwords32 = List.map (fun (off,dw) -> (off, Int32.of_int dw)) dwords in
(* we want to know which regs were trashed *)
let (rv_pairs, regs_init) = gen_init_and_rv_pairs32_no_esp () in
(* generate ctx.delta with filled memory *)
let f_init stmts =
let init = fill_mem sTACK_BASE dwords in
(* we are passing rv_pairs outside to lower redundancy: modified regs will be detected by gadget.ml *)
regs_init @ init
in
let f_finish ctx =
let dwords = dwords32 in
let find_dword v =
let p (off, dw) = dw = v in
let x =
try Some(List.find p dwords)
with Not_found -> None
in
x
in
let print (r,v) =
let sr = reg_to_str r in
(* let _ = Printf.printf "%s = 0x%08lx\n" sr v in *)
()
in
let rv_new = get_regs_no_esp ctx in
let _ = List.map print rv_new in
let _ = flush stderr in
let _ = flush stdout in
(* let rv_pairs = zip Common.rEGS values in *)
let collect rv_list =
let rec aux acc l =
match l with
| (r, Some((off, dw)))::tl -> aux ((r, off)::acc) tl
| (r, None)::tl -> aux acc tl
| [] -> acc
in
aux [] rv_list
in
let l = List.map (fun (r,v) -> (r, find_dword v)) rv_new in
let reg_off_pairs = collect l in
let gadgets = List.map (fun (r,o) -> LoadConst(r, o)) reg_off_pairs in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = false in
let repeats = 1 in
(f_init, f_finish, mem_hax, repeats)
let g_copy_reg () =
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let rv_hash = make_hash (flip rv_pairs) in
(* HAX: We want to detect reg <- esp *)
let _ = Hashtbl.add rv_hash (i32 sTACK_BASE) ESP in
let f_init stmts =
init
in
let f_finish ctx =
let rv_new = get_regs_no_esp ctx in
let dst_src = collect rv_hash rv_new in
(* delete trivial copies *)
let dst_src = List.filter (fun (r1,r2) -> r1 <> r2) dst_src in
let gadgets = List.map (fun (dst,src) -> CopyReg(dst, src)) dst_src in
(* let _ = printf "$$$ found: %d\n" (List.length gadgets) in *)
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = false in
let repeats = 1 in
(f_init, f_finish, mem_hax, repeats)
let calc_op v1 op v2 =
match op with
| ADD -> !+ v1 v2
| SUB -> !- v1 v2
| MUL -> !* v1 v2
| DIV -> !/ v1 v2
| AND -> !& v1 v2
| OR -> !| v1 v2
| XOR -> !^ v1 v2
let calc_pair ((r1,v1),(r2,v2)) =
let f op =
let v = calc_op v1 op v2 in
(v,r1,op,r2)
in
List.map f oPS
(* FIXME: division is incorrect (should handle 64bits *)
let g_binop () =
(* input: list of (r1,v1),(r2,v2) pairs *)
let calc_all l =
(* we don't want to have both BinOp(_,eax,+,edx) and BinOp(_,edx,+,eax) *)
let filter_commutative =
let is_commutative op =
match op with
| ADD | MUL | AND | OR | XOR -> true
| SUB | DIV -> false
in
let p (_,r1,op,r2) =
if is_commutative op then
if cmp_reg r1 r2 = -1 then true else false
else
true
in
p
in
(* FIXME?: overapproximated for now *)
let filter_trivial =
let is_trivial (v,r1,op,r2) =
(* only EAX=EAX/reg *)
let bad_div = op = DIV && ((v = Int32.zero) || r1 <> EAX) in
bad_div || r1 = r2
in
(fun x -> not (is_trivial x))
in
let dump l =
(* let pr (v,r1,op,r2) = Printf.printf "$ %d %s %s %s\n" (Int32.to_int v)
(Common.dump_reg r1) (Common.dump_op op) (Common.dump_reg r2)
in
List.map pr l
*)
()
in
let calculated = List.map calc_pair l in
(* (i32 value, reg1, op, reg2) *)
let calculated = List.concat calculated in
let calculated = List.filter filter_commutative calculated in
let calculated = List.filter filter_trivial calculated in
(* ESP is just a dummy value and needs to be replaced later *)
let wrap (v,r1,op,r2) = BinOp(ESP,r1,op,r2) in
let pairs = List.map (fun x -> let (v,_,_,_) = x in (v, wrap x)) calculated in
let cmp (v1,_) (v2,_) = Int32.compare v1 v2 in
(* ops with equal results are near each other *)
let pairs = List.sort cmp pairs in
(* [(v0,_);(v0,_);(v1,_);(v2,_);(v2,_);(v2,_)] -> [(v0,l0);(v1,l1);(v2,l2)] *)
let gather pairs =
let rec aux acc cur_v cur_l l =
match l with
| hd::tl ->
let v = fst hd in
let x = snd hd in
if v = cur_v then
aux acc cur_v (x::cur_l) tl
else
aux ((cur_v,cur_l)::acc) v [x] tl
| [] ->
if cur_l = [] then acc
else ((cur_v,cur_l)::acc)
in
let partitions =
match pairs with
| [] -> []
| hd::tl ->
let (v,x) = hd in
aux [] v [x] tl
in
partitions
in
let partitions = gather pairs in
let h = make_hash partitions in
h
in
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let rvrv = combos rv_pairs rv_pairs in
(* int32 value -> r1,op,r2 resulting in that value *)
let value_hash = calc_all rvrv in
let f_init stmts =
init
in
let f_finish ctx =
let rv_new = get_regs_no_esp ctx in
(* get a list of (reg, all posible binops resulting in value found in reg) *)
let r_binop_l = collect value_hash rv_new in
let set_dst_in_binops (r, binops) =
let f binop =
match binop with
| BinOp(fake_dst,r1,op,r2) ->
if fake_dst <> ESP then assert false
else BinOp(r,r1,op,r2)
| _ -> assert false
in
let binops = List.map f binops in
binops
in
let binops = List.map set_dst_in_binops r_binop_l in
let gadgets = List.concat binops in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = false in
let repeats = 1 in
(f_init, f_finish, mem_hax, repeats)
let get_global_mem_var () =
let ast_memv,_ = Parser.exp_from_string gLOBAL_MEM in
let memv = unwrap_ast_var ast_memv in
memv
let get_global_mem ctx =
let delta = ctx.delta in
let memv = get_global_mem_var () in
try
let mem = Symbeval.VH.find delta memv in
Some(mem)
with Not_found ->
None
let ast_int_to_byte32 v =
let byte =
match v with
| Ast.Int(v',_) -> Big_int.int32_of_big_int v'
| _ -> assert false
in
if byte < (i32 0) || byte > (i32 255) then
assert false
else
byte
(* input: addr (int32)
* output: byte (int32) under addr in global mem *)
let get_mem_byte mem addr =
let addr = Ast.Int(Big_int.big_int_of_int32 addr, Type.Reg 32) in
let v = Symbeval.Concrete.lookup_mem mem addr Ast.exp_true in (* Ast.exp_true = little endian *)
ast_int_to_byte32 v
(*
let bswap v32 =
let get_byte v i =
let b = (!&) ((!>>) v (i*8)) 0xFF
*)
let get_mem_dword mem addr =
let bytes_in_dword = 4 in
let f i =
let addr = (!+) addr (i32 i) in
get_mem_byte mem addr
in
let bytes = Util.mapn f (bytes_in_dword-1) in
let glue acc b = (!+) ((!<<) acc 8) b in
(* little endian *)
let bytes = List.rev bytes in
let dword = List.fold_left glue (i32 0) bytes in
dword
(* returns a list of addresses with defined bytes *)
let enumerate_mem mem =
let mem_map =
match mem with
| ConcreteMem(mem_map,_) -> mem_map
| _ -> assert false
in
let f k v acc =
let k = int64_to_int32 k in
k::acc
in
let addrs = Symbeval.AddrMap.fold f mem_map [] in
List.sort compare addrs
let get_av_pairs_mem mem =
let addrs = enumerate_mem mem in
let get_dword acc addr =
let dw = get_mem_dword mem addr in
(addr, dw)::acc
in
let av_pairs = List.fold_left get_dword [] addrs in
let print (a,dw) =
let dw = Int32.to_int dw in
let a = Int32.to_int a in
(* let _ = Printf.printf "$$$ [0x%08x] = 0x%08x\n" a dw in *)
()
in
let _ = List.map print av_pairs in
av_pairs
let get_av_pairs_mem' ctx f_mem_get =
let memv = f_mem_get ctx in
match memv with
| Some(memv) -> get_av_pairs_mem memv
| None -> []
let get_av_pairs_mem_init ctx = get_av_pairs_mem' ctx get_global_mem
let get_av_pairs_mem_uninit ctx =
let f_mem_get ctx =
let u_mems = ctx.u_mems in
let memv = get_global_mem_var () in
try
let umem = Symbeval.VH.find u_mems memv in
Some(umem)
with Not_found ->
None
in
get_av_pairs_mem' ctx f_mem_get
(* returns a list of (addr, reg) *)
let match_value_to_reg' f_eq f_pack av_pairs rv_pairs =
let rec aux acc l =
match l with
| hd::tl ->
begin
try
let eq = f_eq hd in
let elem = List.find eq rv_pairs in
let newhd = f_pack hd elem in
aux (newhd::acc) tl
with Not_found ->
aux acc tl
end
| [] -> acc
in
let ar_pairs = aux [] av_pairs in
ar_pairs
let match_value_to_reg l1 l2 =
let f_eq = (fun (addr_,av) (reg,rv) -> av=rv) in
let f_pack = (fun (addr_,v) (reg,_) -> (addr_, reg)) in
match_value_to_reg' f_eq f_pack l1 l2
(* returns a list of (addr_reg, offset, reg) *)
let addr_to_reg_plus_offset ar_pairs rv_pairs =
let rec aux acc l =
match l with
| (addr, reg)::tl ->
let ro_pairs = List.map (fun (reg, rv) -> (reg, (!-) addr rv)) rv_pairs in
let addr_off_src = List.map (fun (addr_reg, off) -> (addr_reg, off, reg)) ro_pairs in
aux (addr_off_src::acc) tl
| [] -> acc
in
(* (addr_reg, offset, src_reg) *)
let ros = aux [] ar_pairs in
List.concat ros
let g_write_mem () =
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let f_init stmts =
init
in
let f_finish ctx =
let av_pairs = get_av_pairs_mem_init ctx in
let ar_pairs = match_value_to_reg av_pairs rv_pairs in
let ar_off_src = addr_to_reg_plus_offset ar_pairs rv_pairs in
let gadgets = List.map (fun (addr_reg, off, src_reg) -> WriteMem(addr_reg, off, src_reg)) ar_off_src in
let rv_new = get_regs_no_esp ctx in
gadgets, (modified_regs rv_pairs rv_new)
in
(* this is to prevent write_mem_op being recognized as write_mem.
without memhax, uninitialized memory = 0, so xor [reg+off], reg' can
be interpreted as mov [reg+off], reg' *)
let mem_hax = true in
let repeats = 2 in (* there are many possibilities for addr_reg+offset *)
(f_init, f_finish, mem_hax, repeats)
let g_read_mem () =
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let f_init stmts =
init
in
let f_finish ctx =
let av_pairs = get_av_pairs_mem_uninit ctx in
let rv_new = get_regs_no_esp ctx in
let ar_pairs = match_value_to_reg av_pairs rv_new in
let ar_off_dst = addr_to_reg_plus_offset ar_pairs rv_pairs in
let gadgets = List.map (fun (addr_reg, off, dst_reg) -> ReadMem(dst_reg, addr_reg, off)) ar_off_dst in
let rv_new = get_regs_no_esp ctx in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = true in
let repeats = 2 in
(f_init, f_finish, mem_hax, repeats)
let g_read_mem_op () =
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let f_init stmts =
init
in
let f_finish ctx =
(* allowing 0/1 will produce many false positives, like reg = reg * 1, reg=reg+0 *)
let good_const v = (!&) v (i32 0x0fffff00) <> (i32 0) in
let rv_new = get_regs_no_esp ctx in
let av_pairs = get_av_pairs_mem_uninit ctx in
let av_pairs = List.filter (fun (a,v) -> good_const v) av_pairs in
let rv_av = combos rv_pairs av_pairs in
(* (i32,reg,op,address) list *)
let calculated = List.map calc_pair rv_av in
let calculated = List.concat calculated in
let l = List.map (fun (i,r,op,addr) -> ((r,op,addr),i)) calculated in
let l = match_value_to_reg l rv_new in
let matched = List.map (fun ((r_old,op,addr),r_new) -> (r_new, r_old, op, addr)) l in
let matched = List.filter (fun (r_new, r_old, _, _) -> r_new = r_old) matched in
let l = List.map (fun (r,_,op,addr) -> (addr, (r,op))) matched in
let l = addr_to_reg_plus_offset l rv_pairs in
let l = List.map (fun (addr_reg, off, (r,op)) -> (r,op,addr_reg,off)) l in
let gadgets = List.map (fun (r_dst, op, addr_reg, off) -> ReadMemOp(r_dst, op, addr_reg, off)) l in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = true in
let repeats = 2 in
(f_init, f_finish, mem_hax, repeats)
let g_write_mem_op () =
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let f_init stmts =
init
in
let f_finish ctx =
(* allowing 0/1 will produce many false positives, like reg = reg * 1, reg=reg+0 *)
let good_const v = (!&) v (i32 0x0fffff00) <> (i32 0) in
let undef_av = get_av_pairs_mem_uninit ctx in
let def_av = get_av_pairs_mem_init ctx in
let f_eq (a1,_) (a2,_) = a1=a2 in
let f_pack (a,v1) (_,v2) = (a,v1,v2) in
(* (addr, before value, after value) list *)
let avv = match_value_to_reg' f_eq f_pack undef_av def_av in
(* if value didn't change, then most likely no arith. op was performed *)
let avv = List.filter (fun (a,v1,v2) -> v1 <> v2) avv in
let avv = List.filter (fun (a,v1,v2) -> good_const v1 && good_const v2) avv in
let calc (a,v_before,v_after) =
let f (reg,rv) =
let g op =
let v = calc_op v_before op rv in
(a,v_before,reg,op,v_after,v)
in
List.map g oPS
in
let l = List.map f rv_pairs in
let l = List.concat l in
let l = List.filter (fun (a,v1,r,op,v2,v3) -> v2 = v3) l in
l
in
let l = List.map calc avv in
let l = List.concat l in
let l = List.map (fun (a,_,reg,op,_,_) -> (a, (reg,op))) l in
let l = addr_to_reg_plus_offset l rv_pairs in
let l = List.map (fun (addr_reg, off, (reg,op)) -> (addr_reg, off, op, reg)) l in
let gadgets = List.map (fun (addr_reg, off, op, reg) -> WriteMemOp(addr_reg, off, op, reg)) l in
let rv_new = get_regs_no_esp ctx in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = true in
let repeats = 2 in
(f_init, f_finish, mem_hax, repeats)
(* AH := SF:ZF:xx:AF:xx:PF:1:CF;
* xx - unknown
* mask: 0xd5
* 2nd youngest bit of EFLAGS is set to 1 (reserved bit) *)
let g_lahf () =
let eflags = str_to_var eFLAGS in
let init_eflags () =
let efl_val = rnd_value () in
let set_efl = set_var eflags efl_val 32 in
set_efl
in
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let set_efl = init_eflags () in
let init = set_efl::init in
let f_init stmts =
init
in
let f_finish ctx =
let mask_efl v =
let v = (v land eFLAGS_MASK) lor 2 in
v
in
let eflv = get_var_int ctx eflags in
let eflv = mask_efl eflv in
(* 2nd bit of eflags is always set *)
let eaxv = get_reg_int32 ctx EAX in
let eaxv = Int32.to_int ((!>>) eaxv 8) in
let ah = mask_efl (eaxv land 0xFF) in
let gadgets =
if eflv = ah then [Lahf]
else []
in
let rv_new = get_regs_no_esp ctx in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = false in
let repeats = 2 in
(f_init, f_finish, mem_hax, repeats)
let g_opesp () =
let (rv_pairs, init) = gen_init_and_rv_pairs32_no_esp () in
let f_init stmts =
init
in
let f_finish ctx =
let old_esp = i32 sTACK_BASE in
let new_esp = get_reg_int32 ctx ESP in
let rv_new = get_regs_no_esp ctx in
(* we care only about esp = esp +- reg *)
let ops = [ADD; SUB] in
let calc v1 (r,v2) =
List.map (fun op -> (calc_op v1 op v2, op, r)) ops
in
let f acc (r,v) =
let l = calc old_esp (r,v) in
l::acc
in
(* (v,op,reg) where v = old_esp op reg *)
let l = List.fold_left f [] rv_pairs in
let l = List.concat l in
(* (stack_fix,op,reg) *)
let l = List.map (fun (v,op,r) -> ((!-) new_esp v, op, r)) l in
let l = List.map (fun (v,op,r) -> (Int32.to_int v,op,r)) l in
(* filter impossible stack_fixes *)
let l = List.filter (fun (sf,op,r) -> sf>=4 && sf < tOO_BIG) l in
let gadgets = List.map (fun (sf,op,r) -> OpEsp(op, r, sf)) l in
gadgets, (modified_regs rv_pairs rv_new)
in
let mem_hax = false in
let repeats = 2 in
(f_init, f_finish, mem_hax, repeats)
let g_list () =
[
g_copy_reg;
g_binop;
g_load_const;
g_write_mem;
g_read_mem;
g_read_mem_op;
g_write_mem_op;
g_lahf;
g_opesp;
]