xref: /linux-tools/drivers/mremap/extract.cpp (revision 74ce4ce33d5b8318cee71b38976a25818e666ff3)
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, &regset);
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(&regset_header, sizeof(regset_header), 1, fp_header);
168             fwrite(&regset.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(&regset_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