I don't see a reason why you shouldn't be able to dump a block to the disk from the stack directly.
Starting with
#include <fcntl.h>
char *block;
int main(void) {
int fd=open("/tmp/myfile", O_WRONLY|O_APPEND|O_CREAT, 0666);
write(fd, block, 0x400000);
close(fd);
}
and continuing with
gcc -m32 -S b.c
you arrive at this b.s file
.LC0:
.string "/tmp/myfile"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $438, 8(%esp)
movl $1089, 4(%esp)
movl $.LC0, (%esp) <--- make sure this is the filename string
call open
movl %eax, 28(%esp)
movl block, %eax <--- and this is the address of your buffer
movl $4194304, 8(%esp)
movl %eax, 4(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call write
movl 28(%esp), %eax
movl %eax, (%esp)
call close
leave
ret
which you could copy to your instrumentation with very few modifications. (You'll probably want to save a few registers and restore them on exit).
Or, compile the program using gcc -static -m32 b.c and objdump -d the resulting executable to find out how the system calls are implemented, then replace the library calls with the direct system calls. This has the additional advantage that you don't have to mess with import lists if your instrumentation modifies a completed executable file.
<push registers you want to save>
mov $438, %edx
mov $1089, %ecx
mov filename, %ebx
mov $0x5, %eax ;5 is system call # for open
call *0x80d66c4 ;this is the system call address pulled from objdump
mov %eax, %esi ;save fd
mov $0x400000, %edx
mov block, %ecx ;your buffer address
mov %eax, %ebx
mov $0x4, %eax ;4 is system call # for write
call *0x80d66c4
mov %esi, %ebx
mov $0x6, eax ;6 is system call # for close
call *0x80d66c4
<pop registers>
This doesn't do any error checking, but you should be ok if you put the file on a local hard disk that has enough space. Also, it appends to the file every time instead of creating it, so you'll have to rm
the file before each run.