Read registers with ruby
A couple of days ago I needed to get the state of the cpu registers of a running process during some specific events. The project I was playing with was written in ruby so I wrote a tiny little module that does just that, gives you the value of the requested cpu register. The module is called reginfo and below is the process I followed to do it.
First I had to write the C part of it, for the instrumentation. A simple way to get the registers is to use ptrace. First we attach to a process, then we get the register, then we detach and finally return the value.
For this to work as a ruby module we have to use the ruby.h
#include "ruby.h"
#include <unistd.h>
#include <linux/ptrace.h>
#include <sys/user.h>
VALUE RegInfo = Qnil;
void Init_reginfo();
VALUE method_getr(VALUE self,VALUE arg,VALUE pid);
void Init_reginfo()
{
RegInfo = rb_define_module("RegInfo");
rb_define_method(RegInfo, "getr", method_getr,2 );
}
VALUE method_getr(VALUE self, VALUE arg, VALUE pid)
{
char* input=RSTRING_PTR(arg);
pid_t process = NUM2INT(pid);
struct user_regs_struct registers;
long out=0;
char outreg[10];
ptrace(PTRACE_ATTACH,process,0,0); //attach to process
waitpid(process,NULL,0);
ptrace(PTRACE_GETREGS,process,®isters,®isters); //get'em
if (!strncasecmp(input,"eax",3)){out = registers.eax;} //make sure we don't cmpr case
else if (!strncasecmp(input,"edx",3)){out = registers.edx;}
else if (!strncasecmp(input,"ebx",3)){out = registers.ebx;}
else if (!strncasecmp(input,"ecx",3)){out = registers.ecx;}
else if (!strncasecmp(input,"ebp",3)){out = registers.ebp;}
else if (!strncasecmp(input,"esi",3)){out = registers.esi;}
else if (!strncasecmp(input,"eip",3)){out = registers.eip;}
else {out = registers.eip;} //default
ptrace(PTRACE_DETACH,process,0,0); //detach from process
snprintf(outreg,10,"%lx",out);
return rb_str_new2(outreg);
}
Next it's straight forward, we create an extconf.rb file which when we execute generates the Makefile which will compile our module.
require 'mkmf'
extension_name = 'reginfo'
dir_config(extension_name)
create_makefile(extension_name)
require 'reginfo'
include RegInfo
pid = fork do
system("tail -f txt")
end
puts getr("eip",pid) #here we get EIP
The above prints something like b7f577d8
You can download reginfo from here, the source code from here and project updates here.
This is a very simple linux module that performs only this specific task, more functionality will be added soon. If you are looking for something a bit more elaborate, have a look at METASM.