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