forked from djrbliss/loki
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathloki_unlok.c
152 lines (120 loc) · 3.7 KB
/
loki_unlok.c
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
/*
* loki_unlok
*
* A utility to revert the changes made by loki_patch.
*
* by Dan Rosenberg (@djrbliss)
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "loki.h"
static unsigned char patch[] = PATCH;
/* Find the original address of the ramdisk, which
* was embedded in the shellcode. */
int find_ramdisk_addr(void *img, int sz)
{
int i, ramdisk = 0;
for (i = 0; i < sz - (sizeof(patch) - 9); i++) {
if (!memcmp((char *)img + i, patch, sizeof(patch)-9)) {
ramdisk = *(int *)(img + i + sizeof(patch) - 5);
break;
}
}
return ramdisk;
}
int loki_unlok(const char* in_image, const char* out_image)
{
int ifd, ofd;
unsigned int orig_ramdisk_size, orig_kernel_size, orig_ramdisk_addr;
unsigned int page_kernel_size, page_ramdisk_size, page_size, page_mask, fake_size;
void *orig;
struct stat st;
struct boot_img_hdr *hdr;
struct loki_hdr *loki_hdr;
ifd = open(in_image, O_RDONLY);
if (ifd < 0) {
printf("[-] Failed to open %s for reading.\n", in_image);
return 1;
}
ofd = open(out_image, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (ofd < 0) {
printf("[-] Failed to open %s for writing.\n", out_image);
return 1;
}
/* Map the original boot/recovery image */
if (fstat(ifd, &st)) {
printf("[-] fstat() failed.\n");
return 1;
}
orig = mmap(0, (st.st_size + 0x2000 + 0xfff) & ~0xfff, PROT_READ|PROT_WRITE, MAP_PRIVATE, ifd, 0);
if (orig == MAP_FAILED) {
printf("[-] Failed to mmap input file.\n");
return 1;
}
hdr = orig;
loki_hdr = orig + 0x400;
if (memcmp(loki_hdr->magic, "LOKI", 4)) {
printf("[-] Input file is not a Loki image.\n");
/* Copy the entire file to the output transparently */
if (write(ofd, orig, st.st_size) != st.st_size) {
printf("[-] Failed to copy Loki image.\n");
return 1;
}
printf("[+] Copied Loki image to %s.\n", out_image);
return 0;
}
page_size = hdr->page_size;
page_mask = hdr->page_size - 1;
/* Infer the size of the fake block based on the newer ramdisk address */
if (hdr->ramdisk_addr > 0x88f00000 || hdr->ramdisk_addr < 0xfa00000)
fake_size = page_size;
else
fake_size = 0x200;
orig_ramdisk_addr = find_ramdisk_addr(orig, st.st_size);
if (orig_ramdisk_addr == 0) {
printf("[-] Failed to find original ramdisk address.\n");
return 1;
}
/* Restore the original header values */
hdr->ramdisk_addr = orig_ramdisk_addr;
hdr->kernel_size = orig_kernel_size = loki_hdr->orig_kernel_size;
hdr->ramdisk_size = orig_ramdisk_size = loki_hdr->orig_ramdisk_size;
/* Erase the loki header */
memset(loki_hdr, 0, sizeof(*loki_hdr));
/* Write the image header */
if (write(ofd, orig, page_size) != page_size) {
printf("[-] Failed to write header to output file.\n");
return 1;
}
page_kernel_size = (orig_kernel_size + page_mask) & ~page_mask;
/* Write the kernel */
if (write(ofd, orig + page_size, page_kernel_size) != page_kernel_size) {
printf("[-] Failed to write kernel to output file.\n");
return 1;
}
page_ramdisk_size = (orig_ramdisk_size + page_mask) & ~page_mask;
/* Write the ramdisk */
if (write(ofd, orig + page_size + page_kernel_size, page_ramdisk_size) != page_ramdisk_size) {
printf("[-] Failed to write ramdisk to output file.\n");
return 1;
}
/* Write the device tree if needed */
if (hdr->dt_size) {
printf("[+] Writing device tree.\n");
/* Skip an additional fake_size (page_size of 0x200) bytes */
if (write(ofd, orig + page_size + page_kernel_size + page_ramdisk_size + fake_size, hdr->dt_size) != hdr->dt_size) {
printf("[-] Failed to write device tree to output file.\n");
return 1;
}
}
close(ifd);
close(ofd);
printf("[+] Output file written to %s\n", out_image);
return 0;
}