summaryrefslogtreecommitdiff
path: root/other/reducebind/reducebind.c
diff options
context:
space:
mode:
authorRoot THC2026-02-24 12:42:47 +0000
committerRoot THC2026-02-24 12:42:47 +0000
commitc9cbeced5b3f2bdd7407e29c0811e65954132540 (patch)
treeaefc355416b561111819de159ccbd86c3004cf88 /other/reducebind/reducebind.c
parent073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff)
initial
Diffstat (limited to 'other/reducebind/reducebind.c')
-rw-r--r--other/reducebind/reducebind.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/other/reducebind/reducebind.c b/other/reducebind/reducebind.c
new file mode 100644
index 0000000..6432670
--- /dev/null
+++ b/other/reducebind/reducebind.c
@@ -0,0 +1,311 @@
1/* reducebind.c - dynamic to static binary conversion utility
2 *
3 * by scut
4 *
5 * BETA SOFTWARE, USE ON YOUR OWN RISK
6 *
7 * x86/linux only so far. some binaries segfault deep in their code, but this
8 * does not seem to relate to the binary size. some binaries that have a 19mb
9 * size statically linked (qt designer for example ;) work, some small
10 * binaries, such as bash do not work.
11 */
12
13#include <sys/types.h>
14#include <sys/ptrace.h>
15#include <sys/wait.h>
16#include <sys/user.h>
17#include <sys/stat.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <errno.h>
21#include <unistd.h>
22#include <string.h>
23#include <elf.h>
24
25#define VERSION "0.1.0"
26
27/*** local prototypes */
28static void elf_dump_new (pid_t pid, const char *pathname_new,
29 const char *pathname_old);
30static void file_advance_roundup (FILE *fp, unsigned int padding);
31static Elf32_Addr elf_get_entrypoint (const char *pathname);
32
33
34int
35main (int argc, char *argv[], char *envp[])
36{
37 char * pathname;
38 char * f_argv[2];
39 pid_t fpid; /* child pid, gets ptraced */
40 struct user regs; /* PTRACE pulled registers */
41 Elf32_Addr entry;
42 char * output = "output";
43
44 fprintf (stderr, "reducebind version "VERSION"\n\n");
45
46 if (argc < 2) {
47 fprintf (stderr, "usage: %s <binary> [output]\n\n", argv[0]);
48
49 exit (EXIT_FAILURE);
50 }
51 pathname = argv[1];
52 if (argc >= 3)
53 output = argv[2];
54
55 entry = elf_get_entrypoint (pathname);
56
57 fpid = fork ();
58 if (fpid < 0) {
59 perror ("fork");
60 exit (EXIT_FAILURE);
61 }
62
63 /* child process.
64 */
65 if (fpid == 0) {
66 if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) {
67 perror ("ptrace PTRACE_TRACEME");
68 exit (EXIT_FAILURE);
69 }
70 fprintf (stderr, " child: TRACEME set\n");
71
72 fprintf (stderr, " child: executing: %s\n", pathname);
73 close (1);
74 dup2 (2, 1);
75
76 /* prepare arguments and environment.
77 */
78 f_argv[0] = pathname;
79 f_argv[1] = NULL;
80
81 putenv ("LD_BIND_NOW=1");
82 execve (f_argv[0], f_argv, envp);
83
84 /* failed ? */
85 perror ("execve");
86 exit (EXIT_FAILURE);
87 }
88
89 wait (NULL);
90
91 memset (&regs, 0, sizeof (regs));
92
93 if (ptrace (PTRACE_GETREGS, fpid, NULL, &regs) < 0) {
94 perror ("ptrace PTRACE_GETREGS");
95 exit (EXIT_FAILURE);
96 }
97 fprintf (stderr, "(%d) [0x%08lx] first stop\n", fpid, regs.regs.eip);
98 fprintf (stderr, "(%d) tracing until entry point is reached (0x%08x)\n",
99 fpid, entry);
100
101 while (regs.regs.eip != entry) {
102 if (ptrace (PTRACE_SINGLESTEP, fpid, NULL, NULL) < 0) {
103 perror ("ptrace PTRACE_SINGLESTEP");
104 exit (EXIT_FAILURE);
105 }
106 wait (NULL);
107
108 memset (&regs, 0, sizeof (regs));
109 if (ptrace (PTRACE_GETREGS, fpid, NULL, &regs) < 0) {
110 perror ("ptrace PTRACE_GETREGS");
111 exit (EXIT_FAILURE);
112 }
113 fprintf (stderr, "\r(%d) [0x%08lx]", fpid, regs.regs.eip);
114 }
115
116 fprintf (stderr, "\n(%d) entry point reached\n", fpid);
117 fprintf (stderr, "(%d) dumping process memory to new ELF ET_EXEC file\n",
118 fpid);
119
120 elf_dump_new (fpid, output, pathname);
121
122 exit (EXIT_SUCCESS);
123}
124
125
126static void
127elf_dump_new (pid_t pid, const char *pathname_new, const char *pathname_old)
128{
129 FILE * fpn;
130 FILE * fpo;
131 FILE * mapsfp;
132 char maps_pathname[32];
133 char map_line[256];
134 Elf32_Ehdr eh;
135 Elf32_Phdr phdr[128];
136 unsigned int pn; /* program header table index */
137
138
139 fpn = fopen (pathname_new, "wb");
140 fpo = fopen (pathname_old, "rb");
141 if (fpn == NULL || fpo == NULL) {
142 perror ("fopen output ELF file creation");
143 exit (EXIT_FAILURE);
144 }
145
146 if (fread (&eh, sizeof (eh), 1, fpo) != 1) {
147 perror ("fread ELF header");
148 exit (EXIT_FAILURE);
149 }
150 fclose (fpo);
151
152 /* kill header values */
153 eh.e_shoff = 0x0; /* we do not need any sections for loading */
154 eh.e_shnum = 0;
155 eh.e_shstrndx = 0;
156
157 /* the program header table will be fixed later */
158 eh.e_phoff = 0;
159 eh.e_phnum = 0;
160
161 fwrite (&eh, sizeof (eh), 1, fpn);
162
163 snprintf (maps_pathname, sizeof (maps_pathname) - 1,
164 "/proc/%d/maps", pid);
165 maps_pathname[sizeof (maps_pathname) - 1] = '\0';
166 mapsfp = fopen (maps_pathname, "r");
167 if (mapsfp == NULL) {
168 perror ("fopen map file");
169 exit (EXIT_FAILURE);
170 }
171
172 while (1) {
173 Elf32_Phdr * ph;
174 unsigned int addr_start,
175 addr_end,
176 addr_walker;
177 char map_perm[8];
178 unsigned char data_saved[sizeof (unsigned long int)];
179
180
181 memset (map_line, '\0', sizeof (map_line));
182 if (fgets (map_line, sizeof (map_line) - 1, mapsfp) == NULL)
183 break;
184 map_line[sizeof (map_line) - 1] = '\0';
185
186 fprintf (stderr, "%s", map_line);
187 if (sscanf (map_line, "%08x-%08x %7[rwxp-] ",
188 &addr_start, &addr_end, map_perm) != 3)
189 {
190 perror ("invalid map-line");
191
192 exit (EXIT_FAILURE);
193 }
194
195 /* we do not need the stack in here.
196 */
197 if (addr_end == 0xc0000000)
198 continue;
199
200 file_advance_roundup (fpn, PAGE_SIZE);
201
202 ph = &phdr[eh.e_phnum];
203 eh.e_phnum += 1;
204 memset (ph, 0x00, sizeof (Elf32_Phdr));
205
206 ph->p_type = PT_LOAD;
207 ph->p_offset = ftell (fpn);
208 ph->p_vaddr = addr_start;
209 ph->p_paddr = 0x0;
210 ph->p_filesz = ph->p_memsz = addr_end - addr_start;
211 ph->p_flags = 0;
212 if (map_perm[0] == 'r')
213 ph->p_flags |= PF_R;
214 if (map_perm[1] == 'w')
215 ph->p_flags |= PF_W;
216 if (map_perm[2] == 'x')
217 ph->p_flags |= PF_X;
218 ph->p_align = PAGE_SIZE;
219
220 /* save segment data, assuming addr is page aligned
221 */
222 for (addr_walker = 0 ; addr_walker < (addr_end - addr_start);
223 addr_walker += sizeof (data_saved))
224 {
225 errno = 0;
226
227 *((unsigned long int *) &data_saved[0]) =
228 ptrace (PTRACE_PEEKDATA, pid,
229 addr_start + addr_walker, NULL);
230
231 if (errno == 0 && fwrite (&data_saved[0],
232 sizeof (data_saved), 1, fpn) != 1)
233 {
234 perror ("fwrite segment");
235
236 exit (EXIT_FAILURE);
237 } else if (errno != 0) {
238 fprintf (stderr,
239 "[0x%08x] invalid PTRACE_PEEKDATA\n",
240 addr_start + addr_walker);
241
242 exit (EXIT_FAILURE);
243 }
244 }
245 }
246
247 fclose (mapsfp);
248
249 /* now write program header table
250 */
251 file_advance_roundup (fpn, PAGE_SIZE);
252 eh.e_phoff = ftell (fpn);
253
254 for (pn = 0 ; pn < eh.e_phnum ; ++pn) {
255 if (fwrite (&phdr[pn], sizeof (Elf32_Phdr), 1, fpn) != 1) {
256 perror ("fwrite program header");
257 exit (EXIT_FAILURE);
258 }
259 }
260
261 fseek (fpn, 0, SEEK_SET);
262 if (fwrite (&eh, sizeof (Elf32_Ehdr), 1, fpn) != 1) {
263 perror ("fwrite final ELF header");
264 exit (EXIT_FAILURE);
265 }
266
267 fclose (fpn);
268 chmod (pathname_new, 0700);
269}
270
271
272static void
273file_advance_roundup (FILE *fp, unsigned int padding)
274{
275 unsigned int pos;
276
277 pos = ftell (fp);
278 if (pos % padding == 0)
279 return;
280
281 pos %= padding;
282 pos = padding - pos;
283
284 fseek (fp, pos, SEEK_CUR);
285}
286
287
288static Elf32_Addr
289elf_get_entrypoint (const char *pathname)
290{
291 FILE * fp;
292 Elf32_Ehdr eh;
293
294
295 fp = fopen (pathname, "rb");
296 if (fp == NULL) {
297 perror ("fopen input ELF file");
298 exit (EXIT_FAILURE);
299 }
300
301 if (fread (&eh, sizeof (eh), 1, fp) != 1) {
302 perror ("fread");
303 exit (EXIT_FAILURE);
304 }
305
306 fclose (fp);
307
308 return (eh.e_entry);
309}
310
311