-
Notifications
You must be signed in to change notification settings - Fork 5
/
integration_tests.rs
187 lines (166 loc) · 9.03 KB
/
integration_tests.rs
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
#[cfg(test)]
mod test {
// You can add more tests here using the a.py script, e.g. run `python3 a.py "mov rax, 0x1234567890abcdef; xor eax, eax"` (select "ts" for setup) to generate a test case
use crate::axecutor::Axecutor;
use crate::helpers::tests::{assert_mem_value, assert_reg_value, ax_test, write_reg_value};
use iced_x86::Register::*;
// push rax; xor rax, rax; pop rbx
ax_test![push_rax_pop_rbx; 0x50, 0x48, 0x31, 0xc0, 0x5b;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x1234567890ABCDEFu64);
write_reg_value!(q; a; RBX; 0x031591385913u64);
// Setup stack
write_reg_value!(q; a; RSP; 0x1000);
a.mem_init_zero(0x1000, 8).unwrap();
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0);
assert_reg_value!(q; a; RBX; 0x1234567890ABCDEFu64);
let rsp = a.reg_read_64(RSP.into()).unwrap();
assert_eq!(rsp, 0x1000);
assert_mem_value!(q; a; rsp; 0x1234567890ABCDEFu64);
};
(FLAG_PF | FLAG_ZF; FLAG_CF | FLAG_SF | FLAG_OF)
];
// mov rax, 5; mov rbx, 7; add rax, rbx
ax_test![mov_rax_5_mov_rbx_7_add_rax_rbx; 0x48, 0xc7, 0xc0, 0x5, 0x0, 0x0, 0x0, 0x48, 0xc7, 0xc3, 0x7, 0x0, 0x0, 0x0, 0x48, 0x1, 0xd8;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x4a644dabfbede0cu64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 12);
assert_reg_value!(q; a; RBX; 7);
};
(FLAG_PF; FLAG_CF | FLAG_ZF | FLAG_SF | FLAG_OF)
];
// mov rax, 5; mov rbx, 7; add rax, rbx; xor rbx, rbx
ax_test![mov_rax_5_mov_rbx_7_add_rax_rbx_xor_rbx_rbx; 0x48, 0xc7, 0xc0, 0x5, 0x0, 0x0, 0x0, 0x48, 0xc7, 0xc3, 0x7, 0x0, 0x0, 0x0, 0x48, 0x1, 0xd8, 0x48, 0x31, 0xdb;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x27b8b455c8f53915u64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0xc);
assert_reg_value!(q; a; RBX; 0);
};
(FLAG_PF | FLAG_ZF; FLAG_CF | FLAG_SF | FLAG_OF)
];
// mov eax, 5; mov rbx, 7; add eax, ebx; xor rbx, rbx
ax_test![mov_eax_5_mov_rbx_7_add_eax_ebx_xor_rbx_rbx; 0xb8, 0x5, 0x0, 0x0, 0x0, 0x48, 0xc7, 0xc3, 0x7, 0x0, 0x0, 0x0, 0x1, 0xd8, 0x48, 0x31, 0xdb;
|a: &mut Axecutor| {
write_reg_value!(d; a; EAX; 0xdf760bf6u32);
};
|a: Axecutor| {
assert_reg_value!(d; a; EAX; 0xc);
assert_reg_value!(q; a; RBX; 0);
};
(FLAG_PF | FLAG_ZF; FLAG_CF | FLAG_SF | FLAG_OF)
];
// Writing to 32-bit registers clears the upper part of the 64-bit register
// mov rax, 0x1234567890abcdef; add eax, 1
ax_test![mov_rax_0x1234567890abcdef_add_eax_1; 0x48, 0xb8, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12, 0x83, 0xc0, 0x1;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x52e6f6b307c35798u64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0x90abcdf0u64);
};
(FLAG_PF | FLAG_SF; FLAG_CF | FLAG_ZF | FLAG_OF)
];
// Writing to non-32-bit register doesn't clear the upper part of the 64-bit register
// mov rax, 0x1234567890abcdef; add ax, 1
ax_test![mov_rax_0x1234567890abcdef_add_ax_1; 0x48, 0xb8, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12, 0x66, 0x83, 0xc0, 0x1;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x23a1a5c719994edfu64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0x1234567890abcdf0u64);
};
(FLAG_PF | FLAG_SF; FLAG_CF | FLAG_ZF | FLAG_OF)
];
// mov rax, 0x1234567890abcdef; xor ax, ax
ax_test![mov_rax_0x1234567890abcdef_xor_ax_ax; 0x48, 0xb8, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12, 0x66, 0x31, 0xc0;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x32b4008fc8254adcu64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0x1234567890ab0000u64);
};
(FLAG_PF | FLAG_ZF; FLAG_CF | FLAG_SF | FLAG_OF)
];
// mov rax, 0x1234567890abcdef; xor eax, eax
ax_test![mov_rax_0x1234567890abcdef_xor_eax_eax; 0x48, 0xb8, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12, 0x31, 0xc0;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0xe0b28ab25656ef15u64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0x0);
};
(FLAG_PF | FLAG_ZF; FLAG_CF | FLAG_SF | FLAG_OF)
];
// mov rax, 4; cmp rax, 3; je .end; nop; mov rax, 42; .end: nop
ax_test![mov_rax_4_cmp_rax_3_je_end_nop_mov_rax_42_end_nop;
0x48, 0xc7, 0xc0, 0x4, 0x0, 0x0, 0x0, 0x48, 0x83, 0xf8, 0x3, 0x74, 0x8, 0x90, 0x48, 0xc7, 0xc0, 0x2a, 0x0, 0x0, 0x0, 0x90;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x4686d92fabdcc717u64);
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0x2a);
};
(0; FLAG_CF | FLAG_PF | FLAG_ZF | FLAG_SF | FLAG_OF)
];
// JMP .Lstart; fn_add: add rax, rbx; ret; .Lstart: mov rax, 1; mov rbx, 2; call fn_add
ax_test![jmp_lstart_fnadd_add_rax_rbx_ret_lstart_mov_rax_1_mov_rbx_2_call_fnadd; 0xeb, 0x4, 0x48, 0x1, 0xd8, 0xc3, 0x48, 0xc7, 0xc0, 0x1, 0x0, 0x0, 0x0, 0x48, 0xc7, 0xc3, 0x2, 0x0, 0x0, 0x0, 0xe8, 0xe9, 0xff, 0xff, 0xff;
|a: &mut Axecutor| {
write_reg_value!(q; a; RAX; 0x50f01be8d7485109u64);
// Setup stack for address
write_reg_value!(q; a; RSP; 0x1000);
a.mem_init_zero(0x1000, 8).expect("Failed to initialize memory");
};
|a: Axecutor| {
assert_reg_value!(q; a; RAX; 0x3);
};
(FLAG_PF; FLAG_CF | FLAG_ZF | FLAG_SF | FLAG_OF)
];
// Note that "\n" is used as string end marker by the program, simulating reading one line from stdin
const STRING_REVERSE_INPUT: &[u8] = b"This is a very interesting string!\n";
const STRING_REVERSE_INPUT_LEN: u64 = STRING_REVERSE_INPUT.len() as u64;
const STRING_REVERSE_INPUT_START_ADDR: u64 = 0x1000;
// See testdata/string_reverse.S for source
ax_test![string_reverse;
0x48, 0x31, 0xdb, 0x48, 0x31, 0xc9, 0x48, 0xf7, 0xc4, 0x0f, 0x00, 0x00, 0x00, 0x74, 0x0f, 0x48, 0x83, 0xec, 0x08, 0xe8, 0x83, 0x00, 0x00, 0x00, 0x48, 0x83,
0xc4, 0x08, 0xeb, 0x05, 0xe8, 0x78, 0x00, 0x00, 0x00, 0x41, 0x8a, 0x1a, 0x80, 0xfb, 0x0a, 0x74, 0x07, 0x53, 0x48, 0x83, 0xc1, 0x01, 0xeb, 0xd4, 0x48, 0x83, 0xf9, 0x00, 0x7f, 0x04,
0x7c, 0x00, 0xeb, 0x27, 0x5b, 0x41, 0x88, 0x1a, 0x48, 0xf7, 0xc4, 0x0f, 0x00, 0x00, 0x00, 0x74, 0x0f, 0x48, 0x83, 0xec, 0x08, 0xe8, 0x36, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x08,
0xeb, 0x05, 0xe8, 0x2b, 0x00, 0x00, 0x00, 0x48, 0x83, 0xe9, 0x01, 0xeb, 0xcf, 0x41, 0xc6, 0x02, 0x0a, 0x48, 0xf7, 0xc4, 0x0f, 0x00, 0x00, 0x00, 0x74, 0x0f, 0x48, 0x83, 0xec, 0x08,
0xe8, 0x0f, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x08, 0xeb, 0x05, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x48, 0x31, 0xc0, 0xc3, 0x50, 0x53, 0x49, 0x8d, 0x1e, 0x4c, 0x01, 0xfb, 0x41, 0x8a,
0x02, 0x88, 0x03, 0x49, 0xff, 0xc7, 0x5b, 0x58, 0xc3, 0x53, 0x49, 0x8d, 0x1b, 0x4c, 0x01, 0xe3, 0x8a, 0x1b, 0x41, 0x88, 0x1a, 0x49, 0xff, 0xc4, 0x5b, 0xc3;
|a: &mut Axecutor| {
assert!(STRING_REVERSE_INPUT.ends_with(b"\n"));
assert!(!STRING_REVERSE_INPUT.is_empty());
// Set up input data
a.mem_init_area(STRING_REVERSE_INPUT_START_ADDR, Vec::from(STRING_REVERSE_INPUT)).expect("Failed to initialize input area memory");
write_reg_value!(q; a; R11; STRING_REVERSE_INPUT_START_ADDR); // input addr
write_reg_value!(q; a; R12; 0); // input progress, how many bytes have been read
write_reg_value!(q; a; R13; STRING_REVERSE_INPUT_LEN); // input length
// Set up output area
a.mem_init_zero(0x2000, STRING_REVERSE_INPUT_LEN).expect("Failed to initialize output area memory");
write_reg_value!(q; a; R14; 0x2000); // output addr
write_reg_value!(q; a; R15; 0); // output progress, how many bytes have been written
// Set up the single char buffer
a.mem_init_zero(0x3000, 1).expect("Failed to initialize char buffer memory");
write_reg_value!(q; a; R10; 0x3000); // char buffer addr
// This should be more depending on the test string
a.init_stack(512).expect("Failed to initialize stack");
};
|a: Axecutor| {
// After running, the output should be reversed
let output = a.mem_read_bytes(0x2000, STRING_REVERSE_INPUT_LEN).expect("Failed to read output area");
#[allow(unused_variables)]
{
let output_str = String::from_utf8(output).expect("Failed to convert output to string");
let input_str = String::from_utf8(Vec::from(STRING_REVERSE_INPUT)).expect("Failed to convert input to string");
crate::helpers::debug::debug_log!("Reversed string {:?} to {:?}", input_str, output_str);
assert_eq!(output_str, STRING_REVERSE_INPUT.iter().rev().skip(1).map(|&b| b as char).collect::<String>() + "\n");
}
}
];
}