1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <sys/ptrace.h>
6 #include <sys/user.h>
7 #include <sys/syscall.h>
8 #include <netinet/in.h>
9 #include <netinet/ip.h>
10 #include <errno.h>
11 #include <linux/elf.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17
18 #include <set>
19 #include <vector>
20 #include <string>
21 using namespace std;
22
23 #define exiterr(err, msg) do{ if(err<0) { perror(msg); exit(1); }} while(0)
24
25 enum {
26 PTRACEXX_REMAP = 1,
27 };
28
29 typedef struct {
30 int pid;
31 unsigned long old_start, old_end;
32 unsigned long new_start, new_end;
33 } RemapDataT;
34
35 typedef union {
36 RemapDataT remap;
37 } IoctlDataT;
38
39 char ibuf[1024*8];
40 typedef struct {
41 unsigned long long start, end, offset;
42 char mode;
43 string name;
44 } MNode;
45 char ns[1024*8];
46 char vmk[128];
load_maps(int pid)47 vector<MNode>* load_maps(int pid) {
48 sprintf(ibuf, "/proc/%d/maps", pid);
49 FILE *fp = fopen(ibuf, "r");
50 char addrs[64], mode[8], offs[16], dev[16];
51 long long inode;
52 unsigned long long start, end, offset;
53 MNode nn;
54 int i, j, k;
55 char m, *p;
56 if (fp==NULL) return NULL;
57 vector<MNode>* ms = new vector<MNode>();
58 while(1) {
59 p = fgets(ibuf, sizeof(ibuf), fp); if (p==NULL) break;
60 k = sscanf(p, "%s %s %s %s %lld %s", addrs, mode, offs, dev, &inode, ns);
61 if (k<5) continue;
62 start=end=offset=0;
63 i=0; while(addrs[i]&&addrs[i]!='-') {
64 if (vmk[addrs[i]]==-1) break;
65 start=start*16+vmk[addrs[i]];
66 i++;
67 } if (i==0||addrs[i]!='-') continue;
68 j=i+1; while(addrs[j]) {
69 if (vmk[addrs[j]]==-1) break;
70 end = end*16+vmk[addrs[j]];
71 j++;
72 } if (j==i+1||addrs[j]!=0) continue;
73 i=0; while(offs[i]) {
74 if (vmk[offs[i]]==-1) break;
75 offset = offset*16+vmk[offs[i]];
76 i++;
77 } if (i==0||offs[i]!=0) continue;
78 m=0; for (i=0; i<4; i++) if (mode[i]!='-') m|=(1<<i);
79 nn.start=start;
80 nn.end = end;
81 nn.offset = offset;
82 nn.mode=m;
83 if (k==5) {
84 nn.name = string();
85 } else if (k==6) {
86 i=0; while(ns[i]) i++;
87 while(i>0&&ns[i-1]!='/') i--;
88 nn.name = string(ns+i);
89 }
90 ms->push_back(nn);
91 }
92 fclose(fp);
93 return ms;
94 }
95
96 char buf[1024*1024];
97 typedef struct {
98 int regset;
99 size_t size;
100 unsigned long offset;
101 } RegHNode;
102
103 typedef struct {
104 unsigned long start, end, offset;
105 unsigned long noffset, doffset;
106 size_t nlen, dsize;
107 unsigned int mode;
108 } MapHNode;
109
110 char mmk[128];
111
main(int argc,char * argv[])112 int main(int argc, char *argv[]) {
113 int pid, err, status, x, i, z, n, fd=-1;
114 unsigned long offset, hlen, dlen;
115 unsigned long faddr = 0x200000000000;
116 struct iovec regset;
117 unsigned long cz, sz, zzz, nstart, nend, _start, _end;
118 int ddd, j, nj;
119 long rc;
120 unsigned long vw, *tp;
121 struct user userinfo;
122 FILE *fp_header=NULL, *fp_binary=NULL;
123 vector<MNode>* mp = NULL;
124 RegHNode regset_header;
125 MapHNode mheader;
126 vector<MapHNode> omp;
127 vector<string> oname;
128 vector<RegHNode> regsets;
129 IoctlDataT d;
130 if (argc<2) { printf("need pid\n"); return 1; }
131 pid = atoi(argv[1]);
132 if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; }
133 err = ptrace(PTRACE_ATTACH, pid, 0, 0);
134 exiterr(err, "fail to attach");
135 printf("attached with %d\n", pid);
136 x = waitpid(-1, &status, __WALL);
137 if (x != pid) {
138 printf("expect pid %d, got %d\n", pid, x);
139 return 1;
140 }
141 fp_header = fopen("./spirity.header", "rb"); if (fp_header==NULL) goto out;
142 fp_binary = fopen("./spirity.binary", "rb"); if (fp_binary==NULL) goto out;
143 fd = open("/dev/ptracexx", O_NONBLOCK);
144 if (fd<0) { perror("fail to open ptracexx\n"); goto out; }
145 // read user info
146 if (fread(&userinfo, sizeof(userinfo), 1, fp_header)!=1) {
147 printf("fail to read userinfo\n"); goto out;
148 }
149 // read reg header
150 regset.iov_base = (void*)buf;
151 while(1) {
152 n = fread(®set_header, sizeof(regset_header), 1, fp_header);
153 if (n!=1) goto out;
154 if (regset_header.regset == -1) break;
155 printf("regset %d: size %ld, data offset 0x%lx\n", regset_header.regset, regset_header.size, regset_header.offset);
156 regsets.push_back(regset_header);
157 // write back
158 // read to buf
159 /*
160 fseek(fp_binary, regset_header.offset, SEEK_SET);
161 n = fread(buf, 1, regset_header.size, fp_binary); if (n!=regset_header.size) {
162 printf("fail to load regset data");
163 goto out;
164 }
165 regset.iov_len = regset_header.size;
166 x = ptrace(PTRACE_SETREGSET, pid, regset_header.regset, ®set);
167 if (x<0) {
168 printf("fail to load regset\n");
169 goto out;
170 }
171 */
172 }
173 // get pid maps
174 memset(vmk, 0xff, sizeof(vmk));
175 for (i='0'; i<='9'; i++) vmk[i]=i-'0';
176 for (i='a'; i<='f'; i++) vmk[i]=i-'a'+10;
177 for (i='A'; i<='F'; i++) vmk[i]=i-'A'+10;
178 mp = load_maps(pid); if (mp==NULL) goto out;
179 // read mmaps from save
180 while(1) {
181 n = fread(&mheader, sizeof(mheader), 1, fp_header); if (n!=1) goto out;
182 if (mheader.start == -1) break;
183 ibuf[0]=0;
184 if (mheader.nlen) {
185 fseek(fp_binary, mheader.noffset, SEEK_SET);
186 fread(ibuf, 1, mheader.nlen, fp_binary);
187 ibuf[mheader.nlen]=0;
188 }
189 printf("[0x%lx,0x%lx) 0x%lx 0x%x namelen(%d):[%s], noffset(0x%lx), doffset(0x%lx)\n",
190 mheader.start, mheader.end, mheader.offset, mheader.mode, mheader.nlen, ibuf,
191 mheader.noffset, mheader.doffset);
192 omp.push_back(mheader);
193 if (ibuf[0]==0) oname.push_back(string());
194 else oname.push_back(string(ibuf));
195 }
196 // align maps
197 n = omp.size();
198 if (mp->size() != n) {
199 printf("size not match, current %d, expect %d\n", mp->size(), omp.size());
200 goto out;
201 }
202 for (i=0; i<n; i++) mmk[i]=0;
203 for (i=0; i<n; i++) printf("0x%lx[%s](0x%lx)---\n", (*mp)[i].start, (*mp)[i].name.c_str(), (*mp)[i].offset);
204 d.remap.pid = pid;
205 for (i=0; i<n; i++) {
206 printf("0x%lx[%s](0x%lx) --->\n", omp[i].start, oname[i].c_str(), omp[i].offset);
207 for (j=0; j<n; j++) if (mmk[j]==0) {
208 if (oname[i]==(*mp)[j].name && omp[i].offset==(*mp)[j].offset) break;
209 }
210 if (j>=n) { printf("no match found\n"); goto out; }
211 printf("found match --->0x%lx[%s](0x%lx)\n", (*mp)[j].start, (*mp)[j].name.c_str(), (*mp)[j].offset);
212 mmk[j]=1;
213 nstart = omp[i].start;
214 nend = omp[i].end;
215 if (omp[i].start!=(*mp)[j].start) {
216 for (nj=0; nj<n; nj++) if (mmk[nj]==0) {
217 _start = (*mp)[nj].start;
218 _end = (*mp)[nj].end;
219 if (_start>=nend) continue;
220 if (_end<=nstart) continue;
221 // remap to faddr
222 d.remap.old_start = _start;
223 d.remap.old_end = _end;
224 d.remap.new_start = faddr;
225 d.remap.new_end = _end-_start+faddr;
226 (*mp)[nj].start = faddr;
227 faddr += (_end-_start);
228 (*mp)[nj].end = faddr;
229 rc = ioctl(fd, PTRACEXX_REMAP, &d);
230 if (rc<0) {
231 printf("fail to remap %ld\n", rc);
232 goto out;
233 }
234 }
235 d.remap.old_start = (*mp)[j].start;
236 d.remap.old_end = (*mp)[j].end;
237 d.remap.new_start = nstart;
238 d.remap.new_end = nend;
239 rc = ioctl(fd, PTRACEXX_REMAP, &d);
240 if (rc<0) {
241 printf("fail to remap %ld\n", rc);
242 goto out;
243 }
244 }
245 // write memory
246 // if ((omp[i].mode&(1<<1))==0) continue;
247 printf("try to copy memory\n");
248 fseek(fp_binary, omp[i].doffset, SEEK_SET);
249 sz = omp[i].dsize; // nend-nstart;
250 while(sz) {
251 cz=sz; if (cz>sizeof(buf)) cz=sizeof(buf);
252 if(fread(buf, 1, cz, fp_binary)!=cz) { printf("fail to load map memory\n"); goto out; }
253 for (zzz=0; zzz<cz; zzz+=8) {
254 // copy word by word
255 vw = *(unsigned long*)(buf+zzz);
256 // printf("write to 0x%lx %x\n", nstart+zzz, ddd);
257 x = ptrace(PTRACE_POKEDATA, pid, nstart+zzz, vw);
258 if (x<0) { perror("fail to poke user memory"); break; }
259 }
260 if (zzz<cz) {
261 sz-=zzz;
262 break;
263 }
264 sz-=cz;
265 nstart+=cz;
266 }
267 if (sz) printf("....%ld left\n", sz);
268 }
269 // load user
270 tp = (unsigned long*)&userinfo;
271 for (i=0; i<sizeof(userinfo); i+=sizeof(unsigned long)) {
272 vw = ptrace(PTRACE_POKEUSER, pid, i, *tp);
273 if (vw==-1) {
274 printf("poke offset %d failed\n", i);
275 perror("error:");
276 goto out;
277 }
278 tp++;
279 }
280 // load reg
281 n = regsets.size();
282 for (i=0; i<n; i++) {
283 regset_header = regsets[i];
284 printf("load regset %d\n", regset_header.regset);
285 // write back
286 // read to buf
287 fseek(fp_binary, regset_header.offset, SEEK_SET);
288 n = fread(buf, 1, regset_header.size, fp_binary); if (n!=regset_header.size) {
289 printf("fail to load regset data");
290 goto out;
291 }
292 regset.iov_len = regset_header.size;
293 x = ptrace(PTRACE_SETREGSET, pid, regset_header.regset, ®set);
294 if (x<0) {
295 printf("fail to load regset\n");
296 goto out;
297 }
298 }
299
300 out:
301 // ptrace(PTRACE_CONT, pid, 0, 0);
302 if (fd>0) close(fd);
303 if (fp_header) fclose(fp_header);
304 if (fp_binary) fclose(fp_binary);
305 return 0;
306 }
307