If you are trying to write to the currently executing file, like this:
open(argv[0], O_RDWR);
You will get the ETXTBSY error. It seems that the only way to do is to unmap all process memory (both text and data):
void do_munmap_and_write(int m0, int l0, int m1,
int l1, int f, int b, int s)
{
int h;
/* munmap */
asm volatile ("int $0x80":: "a"(91), "b"(m0), "c"(l0));
asm volatile ("int $0x80":: "a"(91), "b"(m1), "c"(l1));
/* open */
asm volatile ("int $0x80": "=a"(h): "a"(5), "b"(f), "c"(2));
/* lseek */
asm volatile ("int $0x80":: "a"(19), "b"(h), "c"(0), "d"(2));
/* write */
asm volatile ("int $0x80":: "a"(4), "b"(h), "c"(b), "d"(s));
/* exit */
asm volatile ("int $0x80":: "a"(1));
}
void *get_base(uint32_t addr) {
Elf32_Ehdr *ehdr;
addr &= ~4095;
do {
while (*(uint32_t*)addr != 0x464c457fUL)
addr -= 4096;
ehdr = (Elf32_Ehdr*)addr;
} while (
ehdr->e_ehsize != sizeof(Elf32_Ehdr) ||
ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
ehdr->e_machine != EM_386 ||
ehdr->e_version != EV_CURRENT
);
return (void*)addr;
}
int main(int argc, char **argv, char **envp)
{
uint8_t *p = get_base(main);
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)p;
Elf32_Phdr *phdr = (Elf32_Phdr*)(p + ehdr->e_phoff);
int i;
uint32_t m0, l0, m1, l1;
for (i = 0; i < ehdr->e_phnum; i++) {
if (phdr[i].p_type == PT_LOAD) {
if (phdr[i].p_offset == 0) {
m0 = phdr[i].p_vaddr & 0xffff000;
l0 = phdr[i].p_memsz;
} else {
m1 = phdr[i].p_vaddr & 0xffff000;
l1 = phdr[i].p_memsz;
}
}
}
char *selfexe;
for (i = 0; envp[i + 1]; i++) ;
for (selfexe = envp[i]; *selfexe++; ) ;
uint8_t *op = mmap(0, 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
memcpy(op, do_munmap_and_write, 128);
mprotect(op, 4096, PROT_READ | PROT_EXEC);
((void(*)())op)(m0, l0, m1, l1, selfexe, op, 4096);
}
Surely, the code (which will update argv[0]) and data (that should be written) must be copied somewhere before unmaping (you can saw the branch where you're siting, but carefuly)
Here is the strace:
mmap2(....., MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0xb7fa3000
mprotect(0xb7fa3000, 4096, PROT_READ|PROT_EXEC) = 0
munmap(0x8048000, 2004) = 0
munmap(0x8049000, 272) = 0
open("./a.out", O_RDWR) = 4
lseek(4, 0, SEEK_END) = 9892
write(4, "...\24\315"..., 4096) = 4096
_exit(4) = ?
Have a nice day :-)
No comments:
Post a Comment