-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathinstructions.c
More file actions
130 lines (119 loc) · 4.08 KB
/
instructions.c
File metadata and controls
130 lines (119 loc) · 4.08 KB
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
/*
* instructions.c - functions for modifying or assembling new AARCH64 instructions
*
* Copyright 2020 dayt0n
*
* This file is part of kairos.
*
* kairos is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* kairos is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with kairos. If not, see <https://www.gnu.org/licenses/>.
*/
#include "instructions.h"
void write_opcode(uint8_t* buf, addr_t offset, uint32_t opcode) {
*(uint32_t*)(buf+offset) = opcode;
}
int64_t signExtend(uint64_t x, int M) { // from tihmstar
// count bits
uint64_t extended = (x & 1 << (M-1))>>(M-1);
for (int i=M; i<64; i++)
x |= extended << i;
return x;
}
uint32_t new_insn_adr(addr_t offset,uint8_t rd, int64_t addr) {
uint32_t opcode = 0;
opcode |= SET_BITS(0x10,24); // set adr
opcode |= (rd % (1<<5)); // set rd
// we have a pc rel address
// do difference validations
int64_t diff = addr - offset; // addr - offset to get pc rel
if(diff > 0) {
if(diff > (1LL<<20)) // diff is too long, won't be able to fit
return -1;
else if(-diff > (1LL<<20)) // again, diff is too long but it is a signed int
return -1;
}
opcode |= SET_BITS(BIT_RANGE(diff,0,1),29); // set pos 30-29 to immlo
opcode |= SET_BITS(BIT_RANGE(diff,2,20),5); // set pos 23-5 to immhi
return opcode;
}
uint32_t new_mov_register_insn(uint8_t rd, uint8_t rn, uint8_t rm, int64_t addr) {
uint32_t opcode = 0;
opcode |= SET_BITS(0x1,31); // set up sf
opcode |= SET_BITS(0x150,21); // set up opcode, shift, and N
opcode |= (rd % (1<<5)); // set up rd
opcode |= SET_BITS(rm & 0x1F, 16); // set up rm
opcode |= SET_BITS(rn & 0x1F, 5); // set up rn
opcode |= SET_BITS(addr & 0x3F, 10); // set addr immediate
return opcode;
}
uint32_t new_movk_insn(uint8_t rd, uint16_t imm, uint8_t shift, uint8_t is64) {
uint32_t opcode = 0;
if (is64 != 0)
opcode |= SET_BITS(0x1,31);
else
opcode |= SET_BITS(0x0,31);
opcode |= SET_BITS(0xE5,23);
if (shift != 0) // set hw if needed
opcode |= SET_BITS(shift>>4,21);
opcode |= SET_BITS(imm,5);
opcode |= (rd % (1<<5));
return opcode;
}
uint32_t new_ret_insn(int8_t rnn) { // ret x[rn], default rn value is 13. just set to -1 for default
uint32_t opcode = 0;
if(rnn >= 0) {
if (rnn > (rnn << 3))
printf("[!] Shortening rn for ret intruction\n");
rnn = rnn << 3;
} else
rnn = 30;
uint8_t rn = (uint8_t)rnn;
opcode |= SET_BITS(0xD65F,16);
opcode |= SET_BITS(rn % (1<<5),5);
// after this, everything is 0 so nothing left to do
return opcode;
}
uint32_t new_mov_immediate_insn(uint8_t rd, uint16_t imm, uint8_t is64) { // movz x<rd>, #imm
uint32_t opcode = 0;
if (is64 == 1) // if is64, do a x<rd>, if not, do w<rd>
opcode |= SET_BITS(0x1,31); // set sf
else
opcode |= SET_BITS(0x0,31);
opcode |= SET_BITS(0x294,21); // set opcode, hw
opcode |= SET_BITS(imm,5); // set imm
opcode |= (rd % (1<<5)); // set rd
return opcode;
}
uint32_t replace_adr_addr(addr_t offset, uint32_t insn, int64_t addr) {
uint32_t opcode = 0;
uint8_t rd = get_rd(insn);
opcode = new_insn_adr(offset,rd,addr);
return opcode;
}
uint32_t new_branch(int64_t where, int64_t addr) {
int64_t res = 0;
uint32_t opcode = 0;
if(addr > where) {
opcode |= SET_BITS(0x5,26);
res = (addr - where) / 4;
opcode |= (res % (1<<25));
} else {
opcode |= SET_BITS(0x3,27);
res = (where - addr) / 4;
opcode -= (res % (1<<25));
}
return opcode;
}
uint32_t new_nop() {
return 0xD503201F;
}