1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <sys/ptrace.h>
7 #include <sys/user.h>
8 #include <sys/syscall.h>
9 #include <netinet/in.h>
10 #include <netinet/ip.h>
11 #include <errno.h>
12 #include <linux/elf.h>
13 #include <sys/user.h>
14 #include <string.h>
15
16 #include <set>
17 #include <vector>
18 #include <string>
19 using namespace std;
20
21 #define exiterr(err, msg) do{ if(err<0) { perror(msg); exit(1); }} while(0)
22
23
24 char ibuf[1024*8];
25 typedef struct {
26 unsigned long long start, end, offset;
27 char mode;
28 string name;
29 } MNode;
30 char ns[1024*8];
31 char vmk[128];
load_maps(int pid)32 vector<MNode>* load_maps(int pid) {
33 sprintf(ibuf, "/proc/%d/maps", pid);
34 FILE *fp = fopen(ibuf, "r");
35 char addrs[64], mode[8], offs[16], dev[16];
36 long long inode;
37 unsigned long long start, end, offset;
38 MNode nn;
39 int i, j, k;
40 char m, *p;
41 if (fp==NULL) return NULL;
42 vector<MNode>* ms = new vector<MNode>();
43 while(1) {
44 p = fgets(ibuf, sizeof(ibuf), fp); if (p==NULL) break;
45 k = sscanf(p, "%s %s %s %s %lld %s", addrs, mode, offs, dev, &inode, ns);
46 if (k<5) continue;
47 start=end=offset=0;
48 i=0; while(addrs[i]&&addrs[i]!='-') {
49 if (vmk[addrs[i]]==-1) break;
50 start=start*16+vmk[addrs[i]];
51 i++;
52 } if (i==0||addrs[i]!='-') continue;
53 j=i+1; while(addrs[j]) {
54 if (vmk[addrs[j]]==-1) break;
55 end = end*16+vmk[addrs[j]];
56 j++;
57 } if (j==i+1||addrs[j]!=0) continue;
58 i=0; while(offs[i]) {
59 if (vmk[offs[i]]==-1) break;
60 offset = offset*16+vmk[offs[i]];
61 i++;
62 } if (i==0||offs[i]!=0) continue;
63 m=0; for (i=0; i<4; i++) if (mode[i]!='-') m|=(1<<i);
64 nn.start=start;
65 nn.end = end;
66 nn.mode=m;
67 nn.offset = offset;
68 if (k==5) {
69 nn.name = string();
70 } else if (k==6) {
71 // skip [vvar]
72 i=0; while(ns[i]) i++;
73 while(i>0&&ns[i-1]!='/') i--;
74 nn.name = string(ns+i);
75 }
76 ms->push_back(nn);
77 }
78 fclose(fp);
79 return ms;
80 }
81
82 char buf[1024*1024];
83 typedef struct {
84 int regset;
85 size_t size;
86 unsigned long offset;
87 } RegHNode;
88 typedef struct {
89 unsigned long start, end, offset;
90 unsigned long noffset, doffset;
91 size_t nlen, dsize;
92 unsigned int mode;
93 } MapHNode;
94
95 int regset_ids[] = { NT_PRSTATUS, NT_PRFPREG, NT_PRPSINFO, NT_TASKSTRUCT, NT_AUXV, -1 };
96
map_copy(FILE * out,FILE * mem,unsigned long long start,unsigned long long size)97 int map_copy(FILE* out, FILE* mem, unsigned long long start, unsigned long long size) {
98 int r;
99 size_t n, rn=0;
100 r = fseek(mem, start, SEEK_SET);
101 if (r!=0) return r;
102 while(size) {
103 n = fread(ibuf, 1, sizeof(ibuf), mem); if (n==0) {
104 printf("not enough file to read, left %d/%lld\n", n, size);
105 break;
106 }
107 if (n>size) n=size;
108 fwrite(ibuf, 1, n, out);
109 size-=n;
110 rn+=n;
111 }
112 return rn;
113 }
114
main(int argc,char * argv[])115 int main(int argc, char *argv[]) {
116 int pid, err, status, x, i, z, n;
117 unsigned long offset, hlen, dlen;
118 // struct user_regs_struct regs;
119 struct iovec regset;
120 struct user userinfo;
121 unsigned long *tp, vw, rn;
122 if (argc<2) { printf("need pid\n"); return 1; }
123 pid = atoi(argv[1]);
124 if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; }
125 err = ptrace(PTRACE_ATTACH, pid, 0, 0);
126 exiterr(err, "fail to attach");
127 printf("attached with %d\n", pid);
128 x = waitpid(-1, &status, __WALL);
129 if (x != pid) {
130 printf("expect pid %d, got %d\n", pid, x);
131 return 1;
132 }
133 FILE *fp_header=NULL, *fp_binary=NULL, *fp_mem=NULL;
134 RegHNode regset_header;
135 vector<MNode>* mp = NULL;
136 sprintf(ibuf, "/proc/%d/mem", pid);
137 fp_mem = fopen(ibuf, "rb"); if (fp_mem==NULL) goto out;
138 fp_header = fopen("./spirity.header", "wb"); if (fp_header==NULL) goto out;
139 fp_binary = fopen("./spirity.binary", "wb"); if (fp_binary==NULL) goto out;
140 // load user
141 tp = (unsigned long*)&userinfo;
142 for (i=0; i<sizeof(userinfo); i+=8) {
143 errno = 0;
144 vw = ptrace(PTRACE_PEEKUSER, pid, i, 0);
145 if (errno) {
146 printf("only read %d userinfo --> %ld\n", i, vw);
147 perror("error");
148 break;
149 }
150 *tp=vw; tp++;
151 }
152 offset=0; hlen=0;
153 fwrite(&userinfo, sizeof(userinfo), 1, fp_header);
154 hlen += sizeof(userinfo);
155 // get register
156 regset.iov_base = (void*)buf;
157 for (i=0; ; i++) {
158 z = regset_ids[i];
159 if (z==-1) break;
160 regset.iov_len = sizeof(buf);
161 x = ptrace(PTRACE_GETREGSET, pid, z, ®set);
162 if (x>=0) {
163 printf("saving register set %d, length %d\n", z, regset.iov_len);
164 regset_header.regset = z;
165 regset_header.offset = offset;
166 regset_header.size = regset.iov_len;
167 n = fwrite(®set_header, sizeof(regset_header), 1, fp_header);
168 fwrite(®set.iov_base, 1, regset.iov_len, fp_binary);
169 offset += regset.iov_len;
170 hlen+=sizeof(regset_header);
171 }
172 }
173 regset_header.regset = -1;
174 fwrite(®set_header, sizeof(regset_header), 1, fp_header);
175 hlen+=sizeof(regset_header);
176 // get maps
177 memset(vmk, 0xff, sizeof(vmk));
178 for (i='0'; i<='9'; i++) vmk[i]=i-'0';
179 for (i='a'; i<='f'; i++) vmk[i]=i-'a'+10;
180 for (i='A'; i<='F'; i++) vmk[i]=i-'A'+10;
181 mp = load_maps(pid);
182 MapHNode mheader;
183 if (mp) {
184 for (auto m: *mp) {
185 mheader.start = m.start;
186 mheader.end = m.end;
187 mheader.offset = m.offset;
188 mheader.mode = m.mode;
189 n = m.name.length();
190 mheader.nlen = n;
191 if (n) {
192 strcpy(ns, m.name.c_str());
193 mheader.noffset = offset;
194 n = (n+16)/8*8;
195 fwrite(ns, 1, n, fp_binary);
196 offset+=n;
197 }
198 // read maps if the map is writable
199 //if (mheader.mode&(1<<1)) {
200 dlen = m.end-m.start;
201 mheader.doffset = offset;
202 if (n)
203 printf("try copy from memory address 0x%llx, sizeof %lld [%s]\n", m.start, dlen, m.name.c_str());
204 else
205 printf("try copy from memory address 0x%llx, sizeof %lld []\n", m.start, dlen);
206 rn = map_copy(fp_binary, fp_mem, m.start, dlen);
207 mheader.dsize = rn;
208 offset+=rn;
209 // }
210 fwrite(&mheader, sizeof(mheader), 1, fp_header);
211 hlen += sizeof(mheader);
212 }
213 delete mp;
214 }
215 // mark the end
216 mheader.start = -1;
217 fwrite(&mheader, sizeof(mheader), 1, fp_header);
218 hlen += sizeof(mheader);
219 // ptrace(PTRACE_CONT, pid, 0, 0);
220 ptrace(PTRACE_KILL, pid, 0, 0);
221
222 out:
223 if (fp_header) fclose(fp_header);
224 if (fp_binary) fclose(fp_binary);
225 if (fp_mem) fclose(fp_mem);
226 return 0;
227 }
228