I'm trying to write and debug a C program for an ATMega8 device using the Atmel Studio Simulator.
For example, let's say I'm trying to debug this piece of code:
int main(void)
{
while(1)
{
SPI_transaction(0xFF);
}
}
uint8_t SPI_transaction(unsigned char byte_to_send){
value = byte_to_send;
SPDR = byte_to_send; //Sends command
while (checkBitStatus(SPSR,SPIF) == 0){}; //Do nothing until transfer is completed
value = SPDR; //Receives command
CLEARBIT(SPSR, SPIF);
return value;
}
unsigned char checkBitStatus(unsigned char byte, unsigned char bit){
unsigned char bit_status;
if ((byte & (1 << bit)) == 0){
bit_status = 0;
}
else{
bit_status = 1;
}
return bit_status;
}
This code buids without any problem but when I try to debug this happens:
At some points the program counter goes outside my source files. I've been trying to find out why this happens but I have ot been able yet to find an answer. I leave here the disassembly code for you to have a look. I find it really strange.
Init of main function:
00000024 PUSH R28 Push register on stack
00000025 PUSH R29 Push register on stack
00000026 IN R28,0x3D In from I/O location
00000027 IN R29,0x3E In from I/O location
SPI_transaction(0xFF);
00000028 SER R24 Set Register
00000029 RCALL PC+0x0002 Relative call subroutine
uint8_t SPI_transaction(unsigned char byte_to_send){
0000002B PUSH R28 Push register on stack
0000002C PUSH R29 Push register on stack
0000002D PUSH R1 Push register on stack
0000002E IN R28,0x3D In from I/O location
0000002F IN R29,0x3E In from I/O location
00000030 STD Y+1,R24 Store indirect with displacement
while (checkBitStatus(SPSR,SPIF) == 0){}; //Do nothing until transfer is completed
00000039 NOP No operation
--- No source file -------------------------------------------------------------
0000003A LDI R24,0x2E Load immediate
0000003B LDI R25,0x00 Load immediate
0000003C MOVW R30,R24 Copy register pair
--- No source file -------------------------------------------------------------
0000003D LDD R24,Z+0 Load indirect with displacement
0000003E LDI R22,0x07 Load immediate
0000003F RCALL PC+0x0018 Relative call subroutine
From that it jumps here:
unsigned char checkBitStatus(unsigned char byte, unsigned char bit){
00000057 PUSH R28 Push register on stack
00000058 PUSH R29 Push register on stack
00000059 RCALL PC+0x0001 Relative call subroutine
0000005A PUSH R1 Push register on stack
0000005B IN R28,0x3D In from I/O location
0000005C IN R29,0x3E In from I/O location
0000005D STD Y+2,R24 Store indirect with displacement
0000005E STD Y+3,R22 Store indirect with displacement
if ((byte & (1 << bit)) == 0){
0000005F LDD R24,Y+2 Load indirect with displacement
00000060 MOV R24,R24 Copy register
00000061 LDI R25,0x00 Load immediate
00000062 LDD R18,Y+3 Load indirect with displacement
00000063 MOV R18,R18 Copy register
00000064 LDI R19,0x00 Load immediate
00000065 MOV R0,R18 Copy register
00000066 RJMP PC+0x0003 Relative jump
00000067 ASR R25 Arithmetic shift right
00000068 ROR R24 Rotate right through carry
00000069 DEC R0 Decrement
0000006A BRPL PC-0x03 Branch if plus
0000006B ANDI R24,0x01 Logical AND with immediate
0000006C CLR R25 Clear Register
0000006D SBIW R24,0x00 Subtract immediate from word
0000006E BRNE PC+0x03 Branch if not equal
bit_status = 0;
0000006F STD Y+1,R1 Store indirect with displacement
00000070 RJMP PC+0x0003 Relative jump
bit_status = 1;
00000071 LDI R24,0x01 Load immediate
00000072 STD Y+1,R24 Store indirect with displacement
return bit_status;
00000073 LDD R24,Y+1 Load indirect with displacement
}
00000074 POP R0 Pop register from stack
00000075 POP R0 Pop register from stack
00000076 POP R0 Pop register from stack
00000077 POP R29 Pop register from stack
00000078 POP R28 Pop register from stack
00000079 RET Subroutine return
The function returns to somewhere out my source files:
--- No source file -------------------------------------------------------------
00000040 TST R24 Test for Zero or Minus
00000041 BREQ PC-0x07 Branch if equal
0000003A LDI R24,0x2E Load immediate
0000003B LDI R25,0x00 Load immediate
0000003C MOVW R30,R24 Copy register pair
0000003D LDD R24,Z+0 Load indirect with displacement
0000003E LDI R22,0x07 Load immediate
0000003F RCALL PC+0x0018 Relative call subroutine
And the goes again to CheckBitStatus() function.
Any help will be really appreciated.
Alex
The code executed outside your source is most likely an interrupt service routine for a hardware interrupt handled by an atmel or c standard library. These routinely occur for stuff like USB events that must be handled asynchronously.
Another simple reason for the debugger to display the assembly view and the message "no source file found" , if you attempt to use the debugger while the configuration manager (Under Build tap) has the configuration option set for release, the program compilation will go to the release directory and not to the debug directory.
Related
I have been trying to create an ISR handler following this
tutorial by James Molloy but I got stuck. Whenever I throw a software interrupt, general purpose registers and the data segment register is pushed onto the stack with the variables automatically pushed by the CPU. Then the data segment is changed to the value of 0x10 (Kernel Data Segment Descriptor) so the privilege levels are changed. Then after the handler returns those values are poped. But whenever the value in ds is changed a GPE is thrown with the error code 0x2544 and after a few seconds the VM restarts. (linker and compiler i386-elf-gcc , assembler nasm)
I tried placing hlt instructions in between instructions to locate which instruction was throwing the GPE. After that I was able to find out that the the `mov ds,ax' instruction. I tried various things like removing the stack which was initialized by the bootstrap code to deleting the privilege changing parts of the code. The only way I can return from the common stub is to remove the parts of my code which change the privilege levels but as I want to move towards user mode I still want them to stay.
Here is my common stub:
isr_common_stub:
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
xor eax,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler
xor eax,eax
pop eax
mov ds, ax ; This is the instruction everything fails;
mov es, ax
mov fs, ax
mov gs, ax
popa
iret
My ISR handler macros:
extern isr_handler
%macro ISR_NOERRCODE 1
global isr%1 ; %1 accesses the first parameter.
isr%1:
cli
push byte 0
push %1
jmp isr_common_stub
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli
push byte %1
jmp isr_common_stub
%endmacro
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
...
My C handler which results in "Received interrupt: 0xD err. code 0x2544"
#include <stdio.h>
#include <isr.h>
#include <tty.h>
void isr_handler(registers_t regs) {
printf("ds: %x \n" ,regs.ds);
printf("Received interrupt: %x with err. code: %x \n", regs.int_no, regs.err_code);
}
And my main function:
void kmain(struct multiboot *mboot_ptr) {
descinit(); // Sets up IDT and GDT
ttyinit(TTY0); // Sets up the VGA Framebuffer
asm volatile ("int $0x1"); // Triggers a software interrupt
printf("Wow"); // After that its supposed to print this
}
As you can see the code was supposed to output,
ds: 0x10
Received interrupt: 0x1 with err. code: 0
but results in,
...
ds: 0x10
Received interrupt: 0xD with err. code: 0x2544
ds: 0x10
Received interrupt: 0xD with err. code: 0x2544
...
Which goes on until the VM restarts itself.
What am I doing wrong?
The code isn't complete but I'm going to guess what you are seeing is a result of a well known bug in James Molloy's OSDev tutorial. The OSDev community has compiled a list of known bugs in an errata list. I recommend reviewing and fixing all the bugs mentioned there. Specifically in this case I believe the bug that is causing problems is this one:
Problem: Interrupt handlers corrupt interrupted state
This article previously told you to know the ABI. If you do you will
see a huge problem in the interrupt.s suggested by the tutorial: It
breaks the ABI for structure passing! It creates an instance of the
struct registers on the stack and then passes it by value to the
isr_handler function and then assumes the structure is intact
afterwards. However, the function parameters on the stack belongs to
the function and it is allowed to trash these values as it sees fit
(if you need to know whether the compiler actually does this, you are
thinking the wrong way, but it actually does). There are two ways
around this. The most practical method is to pass the structure as a
pointer instead, which allows you to explicitly edit the register
state when needed - very useful for system calls, without having the
compiler randomly doing it for you. The compiler can still edit the
pointer on the stack when it's not specifically needed. The second
option is to make another copy the structure and pass that
The problem is that the 32-bit System V ABI doesn't guarantee that data passed by value will be unmodified on the stack! The compiler is free to reuse that memory for whatever purposes it chooses. The compiler probably generated code that trashed the area on the stack where DS is stored. When DS was set with the bogus value it crashed. What you should be doing is passing by reference rather than value. I'd recommend these code changes in the assembly code:
irq_common_stub:
pusha
mov ax, ds
push eax
mov ax, 0x10 ;0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp ; At this point ESP is a pointer to where GS (and the rest
; of the interrupt handler state resides)
; Push ESP as 1st parameter as it's a
; pointer to a registers_t
call irq_handler
pop ebx ; Remove the saved ESP on the stack. Efficient to just pop it
; into any register. You could have done: add esp, 4 as well
pop ebx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa
add esp, 8
sti
iret
And then modify irq_handler to use registers_t *regs instead of registers_t regs :
void irq_handler(registers_t *regs) {
if (regs->int_no >= 40) port_byte_out(0xA0, 0x20);
port_byte_out(0x20, 0x20);
if (interrupt_handlers[regs->int_no] != 0) {
interrupt_handlers[regs->int_no](*regs);
}
else
{
klog("ISR: Unhandled IRQ%u!\n", regs->int_no);
}
}
I'd actually recommend each interrupt handler take a pointer to registers_t to avoid unnecessary copying. If your interrupt handlers and the interrupt_handlers array used function that took registers_t * as the parameter (instead of registers_t) then you'd modify the code:
interrupt_handlers[r->int_no](*regs);
to be:
interrupt_handlers[r->int_no](regs);
Important: You have to make these same type of changes for your ISR handlers as well. Both the IRQ and ISR handlers and associated code have this same problem.
I am trying to upload this simple assembly program:
.global _start
.text
reset: b _start
undefined: b undefined
software_interrupt: b software_interrupt
prefetch_abort: b prefetch_abort
data_abort: b data_abort
nop
interrupt_request: b interrupt_request
fast_interrupt_request: b fast_interrupt_request
_start:
mov r0, #0
mov r1, #1
increase:
add r0, r0, r1
cmp r0, #10
bne increase
decrease:
sub r0, r0, r1
cmp r0, #0
bne decrease
b increase
stop: b stop
to my LPC4088 (I am using Embedded artists LPC4088 QSB) via SEGGER's JLink so I could later debug it using GDB.
First I compiled my sources with all the debugging symbols using GCC toolchain:
arm-none-eabi-as -g -gdwarf-2 -o program.o program.s
arm-none-eabi-ld -Ttext=0x0 -o program.elf program.o
arm-none-eabi-objcopy -O binary program.elf program.bin
But uploading binary program.bin to LPC4088 was unsuccessful. Then user #old_timer reminded me in the comments that LPC4088's boot ROM does a checksum test after every reset like described on a page 876 of LPC4088 user manual:
So I mad sure my binary would pass a checksum test by following steps described here. So I first created a C source file checksum.c:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv) {
int fw, count, crc;
char buf[28];
fw = open(argv[1], O_RDWR);
// read fist 28 bytes
read(fw, &buf, 28);
// find 2's complement of entries 0 to 6
for (count=0, crc=0; count < 7; count++) {
crc += *((int*)(buf+count*4));
}
crc = (~crc) + 1;
// write it at offset 0x0000001C
lseek(fw, 0x0000001C, SEEK_SET);
write(fw, &crc, 4);
close(fw);
return 0;
}
compiled it using gcc -o checksum.bin checksum.c and then I fed it the original program.bin as an argument like this ./checksum.bin program.bin. So I got a modified program.bin which really had a value at 0x1C modified! Here is the comparison of the original:
and the modified version:
So the value at 0x1C was modified from 0xFEFFFFEA to 0x0400609D. This is all that was modified as can be seen from the images.
I then opened terminal application JLinkExe which presented a prompt. In the prompt I:
powered on my board using power on,
connected to the LPC4088 using command connect,
halted the MCPU using command h,
erased entire FLASH memory using command erase,
uploaded my modified binary to FLASH loadbin program.bin 0x0,
set the program counter to start at the beginning SetPC 0x4.
started stepping into the program using s.
When I started stepping into the program in first step I got some errors as can be seen at the end of the procedure inside JLinkExe prompt:
SEGGER J-Link Commander V6.30a (Compiled Jan 31 2018 18:14:21)
DLL version V6.30a, compiled Jan 31 2018 18:14:14
Connecting to J-Link via USB...O.K.
Firmware: J-Link V9 compiled Jan 29 2018 15:41:50
Hardware version: V9.30
S/N: 269300437
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref = 3.293V
Type "connect" to establish a target connection, '?' for help
J-Link>connect
Please specify device / core. <Default>: LPC4088
Type '?' for selection dialog
Device>
Please specify target interface:
J) JTAG (Default)
S) SWD
TIF>
Device position in JTAG chain (IRPre,DRPre) <Default>: -1,-1 => Auto-detect
JTAGConf>
Specify target interface speed [kHz]. <Default>: 4000 kHz
Speed>
Device "LPC4088" selected.
Connecting to target via JTAG
TotalIRLen = 4, IRPrint = 0x01
JTAG chain detection found 1 devices:
#0 Id: 0x4BA00477, IRLen: 04, CoreSight JTAG-DP
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x24770011)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0xE00FF000
CPUID register: 0x410FC241. Implementer code: 0x41 (ARM)
Found Cortex-M4 r0p1, Little endian.
FPUnit: 6 code (BP) slots and 2 literal slots
CoreSight components:
ROMTbl[0] # E00FF000
ROMTbl[0][0]: E000E000, CID: B105E00D, PID: 000BB00C SCS-M7
ROMTbl[0][1]: E0001000, CID: B105E00D, PID: 003BB002 DWT
ROMTbl[0][2]: E0002000, CID: B105E00D, PID: 002BB003 FPB
ROMTbl[0][3]: E0000000, CID: B105E00D, PID: 003BB001 ITM
ROMTbl[0][4]: E0040000, CID: B105900D, PID: 000BB9A1 TPIU
ROMTbl[0][5]: E0041000, CID: B105900D, PID: 000BB925 ETM
Cortex-M4 identified.
J-Link>h
PC = 000001B2, CycleCnt = 825F97DB
R0 = 00000000, R1 = 20098038, R2 = 2009803C, R3 = 000531FB
R4 = 00000000, R5 = 00000000, R6 = 12345678, R7 = 00000000
R8 = 6C2030E3, R9 = 0430DB64, R10= 10000000, R11= 00000000
R12= 899B552C
SP(R13)= 1000FFF0, MSP= 1000FFF0, PSP= 6EBAAC08, R14(LR) = 00000211
XPSR = 21000000: APSR = nzCvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00
FPS0 = 93310C50, FPS1 = 455D159C, FPS2 = 01BA3FC2, FPS3 = E851BEED
FPS4 = D937E8F4, FPS5 = 82BD7BF6, FPS6 = 8F16D263, FPS7 = B0E8C039
FPS8 = 302C0A38, FPS9 = 8007BC9C, FPS10= 9A1A276F, FPS11= 76C9DCFE
FPS12= B2FFFA20, FPS13= B55786BB, FPS14= 2175F73E, FPS15= 5D35EC5F
FPS16= 98917B32, FPS17= C964EEB6, FPS18= FEDCA529, FPS19= 1703B679
FPS20= 2F378232, FPS21= 973440E3, FPS22= 928C911C, FPS23= 20A1BF55
FPS24= 4AE3AD0C, FPS25= 4F47CC1E, FPS26= C7B418D5, FPS27= 3EAB9244
FPS28= 73C795D0, FPS29= A359C85E, FPS30= 823AEA80, FPS31= EC9CBCD5
FPSCR= 00000000
J-Link>erase
Erasing device (LPC4088)...
J-Link: Flash download: Only internal flash banks will be erased.
To enable erasing of other flash banks like QSPI or CFI, it needs to be enabled via "exec EnableEraseAllFlashBanks"
Comparing flash [100%] Done.
Erasing flash [100%] Done.
Verifying flash [100%] Done.
J-Link: Flash download: Total time needed: 3.357s (Prepare: 0.052s, Compare: 0.000s, Erase: 3.301s, Program: 0.000s, Verify: 0.000s, Restore: 0.002s)
Erasing done.
J-Link>loadbin program.bin 0x0
Downloading file [program.bin]...
Comparing flash [100%] Done.
Erasing flash [100%] Done.
Programming flash [100%] Done.
Verifying flash [100%] Done.
J-Link: Flash download: Bank 0 # 0x00000000: 1 range affected (4096 bytes)
J-Link: Flash download: Total time needed: 0.076s (Prepare: 0.056s, Compare: 0.001s, Erase: 0.000s, Program: 0.005s, Verify: 0.000s, Restore: 0.012s)
O.K.
J-Link>SetPC 0x4
J-Link>s
**************************
WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1.
**************************
J-Link>s
****** Error: Failed to read current instruction.
J-Link>s
****** Error: Failed to read current instruction.
J-Link>s
****** Error: Failed to read current instruction.
J-Link>
So this code must have come from somewhere and it may be the LPC4088's Boot ROM which is remapped to 0x0 at boot time as is stated on page 907 of the LPC4088 user manual:
Do you have any idea on how to overcome this Boot ROM & checksum problem, so I could debug my program normally?
After a while I found out that warning:
**************************
WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1.
**************************
is actually saying that I am trying to execute ARM instruction on a Cortex-M4 which is Thumb only! This T-bit mentioned in the warning is described on page 100 of ARMv7-M architecture reference manual:
And this is exactly what user #old_timer is saying.
You are trying to run arm instructions (0xExxxxxxxx is a big giveaway, not to mention the exception table being a lot of 0xEAxxxxxx instructions) on a cortex-m4. The cortex-m boots differently (vector table rather than executable instructions) and is thumb only (the thumb2 extensions in armv7-m are also...just thumb, dont be confused by that, what thumb2 extensions do matter but the early/original thumb is portable across all of them). So whether or not you need an additional checksum somewhere like older ARM7TDMI based NXP chips in order for the bootloader to allow the user/application code to run, you first need something that will run on the cortex-m4.
start with this, yes I know you have a cortex-m4 use cortex-m0 for now.
so.s
.cpu cortex-m0
.thumb
.thumb_func
.globl _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
# ...
.thumb_func
hang: b hang
.thumb_func
reset:
mov r1,#0
outer:
mov r0,#0xFF
inner:
nop
nop
add r1,#1
sub r0,#1
bne inner
nop
nop
b outer
build
arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -Ttext=0 so.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf -O binary so.bin
examine so.list to make sure the vector table is correct.
00000000 <_start>:
0: 20001000 andcs r1, r0, r0
4: 0000000f andeq r0, r0, pc
8: 0000000d andeq r0, r0, sp
0000000c <hang>:
c: e7fe b.n c <hang>
0000000e <reset>:
e: 2100 movs r1, #0
00000010 <outer>:
10: 20ff movs r0, #255 ; 0xff
00000012 <inner>:
12: 46c0 nop ; (mov r8, r8)
14: 46c0 nop ; (mov r8, r8)
16: 3101 adds r1, #1
18: 3801 subs r0, #1
1a: d1fa bne.n 12 <inner>
1c: 46c0 nop ; (mov r8, r8)
1e: 46c0 nop ; (mov r8, r8)
20: e7f6 b.n 10 <outer>
The reset entry point is 0x00E which is correctly indicated in the vector table at offset 0x4 as 0x00F. You can flash it to 0x000 and then reset and see if it works (need a debugger to stop it to see if it is stepping through that code).
To run from sram there is nothing position dependent here, so you can load the .bin as is to 0x20000000 and execute from 0x2000000E (or whatever address your toolchain ends up creating for the reset entry point).
Or you can remove the vector table
.cpu cortex-m0
.thumb
.thumb_func
reset:
mov r1,#0
outer:
mov r0,#0xFF
inner:
nop
nop
add r1,#1
sub r0,#1
bne inner
nop
nop
b outer
And link with -Ttext=0x20000000, then download to sram and start execution with the debugger at 0x20000000.
You should see r0 counting some, r1 should just keep counting forever then roll over and keep counting so if you stop it check the registers, resume, stop, etc you should see that activity.
I'm on MAC OSX and I'm trying to call through assembly the execve syscall..
His opcode is 59 .
In linux I have to set opcode into eax, then parameters into the others registers, but here I have to put the opcode into eax and push parameters into the stack from right to left.
So I need execve("/bin/sh",NULL,NULL), I found somewhere that with assembly null=0, so I put null into 2nd and 3rd parameters.
global start
section .text
start:
jmp string
main:
; 59 opcode
; int execve(char *fname, char **argp, char **envp);
pop ebx ;stringa
push 0x0 ;3rd param
push 0x0 ;2nd param
push ebx ;1st param
add eax,0x3b ;execve opcode
int 0x80 ;interupt
sub eax,0x3a ; exit opcode
int 0x80
string:
call main
db '/bin/sh',0
When I try to execute it say:
Bad system call: 12
32-bit programs on BSD (on which OS/X is based) requires you to push an extra 4 bytes onto the stack if you intend to call int 0x80 directly. From the FreeBSD documentation you will find this:
By default, the FreeBSD kernel uses the C calling convention. Further, although the kernel is accessed using int 80h, it is assumed the program will call a function that issues int 80h, rather than issuing int 80h directly.
[snip]
But assembly language programmers like to shave off cycles. The above example requires a call/ret combination. We can eliminate it by pushing an extra dword:
open:
push dword mode
push dword flags
push dword path
mov eax, 5
push eax ; Or any other dword
int 80h
add esp, byte 16
When calling int 0x80 you need to adjust the stack pointer by 4. Pushing any value will achieve this. In the example they just do a push eax. Before your calls to int 0x80 push 4 bytes onto the stack.
Your other problem is that add eax,0x3b for example requires EAX to already be zero which is almost likely not the case. To fix that add an xor eax, eax to the code.
The fixes could look something like:
global start
section .text
start:
jmp string
main:
; 59 opcode
; int execve(char *fname, char **argp, char **envp);
xor eax, eax ;zero EAX
pop ebx ;stringa
push 0x0 ;3rd param
push 0x0 ;2nd param
push ebx ;1st param
add eax,0x3b ;execve opcode
push eax ;Push a 4 byte value after parameters per calling convention
int 0x80 ;interupt
sub eax,0x3a ; exit opcode
push eax ;Push a 4 byte value after parameters per calling convention
; in this case though it won't matter since the system call
; won't be returning
int 0x80
string:
call main
db '/bin/sh',0
Shellcode
Your code is actually called the JMP/CALL/POP method and is used for writing exploits. Are you writing an exploit or did you just find this code online? If it is intended to be used as shell code you would need to avoid putting a 0x00 byte in the output string. push 0x00 will encode 0x00 bytes in the generated code. To avoid this we can use EAX which we are now zeroing out and push it on the stack. As well you won't be able to NUL terminate the string so you'd have to move a NUL(0) character into the string. One way after zeroing EAX and popping EBX is to move zero to the end of the string manually with something like mov [ebx+7], al. Seven is the index after the end of the string /bin/sh. Your code would then look like this:
global start
section .text
start:
jmp string
main:
; 59 opcode
; int execve(char *fname, char **argp, char **envp);
xor eax, eax ;Zero EAX
pop ebx ;stringa
mov [ebx+7], al ;append a zero onto the end of the string '/bin/sh'
push eax ;3rd param
push eax ;2nd param
push ebx ;1st param
add eax,0x3b ;execve opcode
push eax
int 0x80 ;interupt
sub eax,0x3a ; exit opcode
push eax
int 0x80
string:
call main
db '/bin/sh',1
You are using a 64 bit syscall numbers and a 32 bit instruction to jump to the syscall. That is not going to work.
For 32 bit users:
opcode for Linux/MacOS execve: 11
instruction to call syscall: int 0x80
For 64 bit users:
opcode for Linux execve: 59 (MacOS 64-bit system calls also have a high bit set).
instruction to call syscall: syscall
The method for passing args to system calls is also different: 32-bit uses the stack, 64-bit uses similar registers to the function-calling convention.
I'm trying to programatically generate a stack trace. When my users are having a crash, in particular a random one, it's hard to talk them through the process of getting a dump so I can fix the problem. In the past once they would send me the trace I would cross reference the addresses in it to the Intermediate/foo.map file to figure out which function was the problem (is that the best way?)
I built a library from various examples I found around the net, to output a minidump to make my job easier. I staged a crash, but the stack trace I get from the minidump file is wildly different from a live stack trace I get from attaching windbg. Examples of both are below:
MiniDump.dmp:
KERNELBASE.dll!76a6c42d()
[Frames below may be incorrect and/or missing, no symbols loaded for KERNELBASE.dll]
KERNELBASE.dll!76a6c42d()
kernel32.dll!75bd14bd()
game.exe!00759035()
game.exe!00575ba3()
WinDbg.exe:
0:000:x86> kv
ChildEBP RetAddr Args to Child
00186f44 00bc8ea9 19460268 0018a9b7 03f70a28 Minidump!crashme+0x2 (FPO: [0,0,0]) (CONV: cdecl) [c:\project\debug\minidump.cpp # 68]
0018795c 00b9ef31 0018796c 03f56c00 6532716d Main!LoadPlugin+0x339 (FPO: [1,642,4]) (CONV: cdecl) [c:\project\main\pluginloader.cpp # 129]
00188968 00b9667d 19460268 0018a9ac 00000000 Main!Command+0x1f1 (FPO: [2,1024,4]) (CONV: cdecl) [c:\project\main\commands.cpp # 2617]
*** WARNING: Unable to verify checksum for C:\Game\game.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Game\game.exe
0018b1a8 005b5095 19460268 0018beac 00000000 Main!Hook::Detour+0x52d (FPO: [2,2570,0]) (CONV: thiscall) [c:\project\main\hook.cpp # 275]
WARNING: Stack unwind information not available. Following frames may be wrong.
0018b1b4 00000000 19495200 19495200 00000006 game+0x1b5095
game.exe is not mine, and I don't have the source/symbols. The Main.dll is injected into game.exe and it provides front end functionality to load additional DLLs from within the game. The debug code, and the staged crash is in Minidump.dll. After Main.dll loads Minidump it calls AfterLoad(), which sets the exception filter, and then triggers the crash. The relevant minidump code is below:
When I opened the MiniDump.dmp I pointed it to all of my symbol files (with the exception of game.exe, which I don't have) and that part seems like it's working. I do point it to the game.exe binary since I have that. The stack trace I get out of it just really isn't helpful though. My ultimate goal is that the user can just load the DLL, cause the crash, and email the dump file to me. Then I'll attach the symbol files and binaries and be able to diagnose the problem for them. Am I doing something wrong, or is it just not possible to get what I want.
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
LONG WINAPI WriteDumpFilter(struct _EXCEPTION_POINTERS *pExceptionPointers)
{
HANDLE hFile = NULL;
HMODULE hDll = NULL;
MINIDUMPWRITEDUMP pMiniDumpWriteDump = NULL;
_MINIDUMP_EXCEPTION_INFORMATION ExceptionInformation = {0};
//load MiniDumpWriteDump
hDll = LoadLibrary(TEXT("DbgHelp.dll"));
pMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(hDll, "MiniDumpWriteDump");
//create output file
hFile = CreateFile( _T( "C:\\temp\\MiniDump.dmp"),
GENERIC_READ|GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
//bail if we don't have a file
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
//get exception information
ExceptionInformation.ThreadId = GetCurrentThreadId();
ExceptionInformation.ExceptionPointers = pExceptionPointers;
ExceptionInformation.ClientPointers = TRUE;
//write the debug dump
pMiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpWithFullMemory, &ExceptionInformation,
NULL, NULL );
//close the debug output file
CloseHandle(hFile);
}
return EXCEPTION_EXECUTE_HANDLER;
}
VOID crashme() {int* foo = 0; *foo = 0;}
VOID AfterLoad(VOID)
{
SetUnhandledExceptionFilter(WriteDumpFilter);
crashme();
}
I tried to trim some of the fat out of all the details to simplify the problem, but I can be more explicit if needed. I found the good write-up on CodeProject, and I tried finding more background information to read in order to help me understand the problem, but what I could find didn't help me understand they were just step-by-steps to get it running (which is already is). Anyone have any idea what I'm doing wrong, or maybe point me to relevant reading?
After Sergei's suggestion I did .ecxr in windbg and got better output, but it still doesn't match the trace I get when I hook windbg straight up to the process and trigger the crash. Here is the minidump trace;
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0018e774 00759035 e06d7363 00000001 00000003 KERNELBASE!RaiseException+0x58
0018e7b4 00575ba3 00000000 00000000 00000001 game+0x359035
0018fc50 0057788a 009855ef 0018fdcb 00000001 game+0x175ba3
0018fc78 77b7e013 012d9230 002d91d0 002d9200 game+0x17788a
0018fc90 77ba9567 00290000 00000000 002d91d0 ntdll!RtlFreeHeap+0x7e
0018fd6c 0076ece2 0018ff78 007e1b7e ffffffff ntdll!LdrRemoveLoadAsDataTable+0x4e0
002bbc38 5c306174 61666544 00746c75 5d4c3055 game+0x36ece2
002bbc3c 61666544 00746c75 5d4c3055 8c000000 0x5c306174
002bbc40 00746c75 5d4c3055 8c000000 00000101 0x61666544
002bbc44 5d4c3055 8c000000 00000101 01000000 game+0x346c75
002bbc48 8c000000 00000101 01000000 00000000 0x5d4c3055
002bbc4c 00000000 01000000 00000000 0000006e 0x8c000000
and the trace from attaching the debugger to the process
0:000:x86> kv
ChildEBP RetAddr Args to Child
00186f44 00bc8ea9 19460268 0018a9b7 03f70a28 Minidump!crashme+0x2 (FPO: [0,0,0]) (CONV: cdecl) [c:\project\debug\minidump.cpp # 68]
0018795c 00b9ef31 0018796c 03f56c00 6532716d Main!LoadPlugin+0x339 (FPO: [1,642,4]) (CONV: cdecl) [c:\project\main\pluginloader.cpp # 129]
00188968 00b9667d 19460268 0018a9ac 00000000 Main!Command+0x1f1 (FPO: [2,1024,4]) (CONV: cdecl) [c:\project\main\commands.cpp # 2617]
*** WARNING: Unable to verify checksum for C:\Game\game.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Game\game.exe
0018b1a8 005b5095 19460268 0018beac 00000000 Main!Hook::Detour+0x52d (FPO: [2,2570,0]) (CONV: thiscall) [c:\project\main\hook.cpp # 275]
WARNING: Stack unwind information not available. Following frames may be wrong.
0018b1b4 00000000 19495200 19495200 00000006 game+0x1b5095
I don't have the source for game.exe (I have it for the DLLs which is where the error is), but I decompiled game.exe and here is what is at game+0x359035.
.text:00759001 ; =============== S U B R O U T I N E =======================================
.text:00759001
.text:00759001 ; Attributes: library function bp-based frame
.text:00759001
.text:00759001 ; __stdcall _CxxThrowException(x, x)
.text:00759001 __CxxThrowException#8 proc near ; CODE XREF: .text:0040100Fp
.text:00759001 ; sub_401640+98p ...
.text:00759001
.text:00759001 dwExceptionCode = dword ptr -20h
.text:00759001 dwExceptionFlags= dword ptr -1Ch
.text:00759001 nNumberOfArguments= dword ptr -10h
.text:00759001 Arguments = dword ptr -0Ch
.text:00759001 var_8 = dword ptr -8
.text:00759001 var_4 = dword ptr -4
.text:00759001 arg_0 = dword ptr 8
.text:00759001 arg_4 = dword ptr 0Ch
.text:00759001
.text:00759001 push ebp
.text:00759002 mov ebp, esp
.text:00759004 sub esp, 20h
.text:00759007 mov eax, [ebp+arg_0]
.text:0075900A push esi
.text:0075900B push edi
.text:0075900C push 8
.text:0075900E pop ecx
.text:0075900F mov esi, offset unk_853A3C
.text:00759014 lea edi, [ebp+dwExceptionCode]
.text:00759017 rep movsd
.text:00759019 mov [ebp+var_8], eax
.text:0075901C mov eax, [ebp+arg_4]
.text:0075901F mov [ebp+var_4], eax
.text:00759022 lea eax, [ebp+Arguments]
.text:00759025 push eax ; lpArguments
.text:00759026 push [ebp+nNumberOfArguments] ; nNumberOfArguments
.text:00759029 push [ebp+dwExceptionFlags] ; dwExceptionFlags
.text:0075902C push [ebp+dwExceptionCode] ; dwExceptionCode
.text:0075902F call ds:RaiseException
.text:00759035 pop edi
.text:00759036 pop esi
.text:00759037 leave
.text:00759038 retn 8
.text:00759038 __CxxThrowException#8 endp
My error that I'm triggering is in Minidump.dll, but this code at the top of the stack is in game.exe. There could be plenty going on inside the game.exe that I'm unaware of, could it maybe be hijacking the error that I'm triggering somehow? I.E., I trigger the error in the DLL, but something setup in the game.exe captures program flow before the exception filter that writes the minidump is called?
If that's the case, when I attach the debugger to the process, trigger the error and get the right output that points to the error being in my DLL, then that means game.exe isn't capturing the program flow before the debugger can do the trace. How could I make my minidump code behave the same way... This is getting into territory I'm not terribly familiar with. Any ideas?
I chased further back, and the function calling that one, has this line in it:
.text:00575A8D mov esi, offset aCrashDumpTooLa ; "Crash dump too large to send.\n"
So, I think game.exe is hijacking the exception to do it's own dump before my code tries to get the dump. And then my dumps trace is just a trace of game.exe's dump process...
Answer
I've got it figured out. I'm not sure how to answer my own post, so here is the deal.
.text:0057494A push offset aDbghelp_dll ; "DbgHelp.dll"
.text:0057494F call ds:LoadLibraryA
.text:00574955 test eax, eax
.text:00574957 jz short loc_5749C8
.text:00574959 push offset aMinidumpwrited ; "MiniDumpWriteDump"
.text:0057495E push eax ; hModule
.text:0057495F call ds:GetProcAddress
.text:00574965 mov edi, eax
.text:00574967 test edi, edi
.text:00574969 jz short loc_5749C8
.text:0057496B mov edx, lpFileName
.text:00574971 push 0 ; hTemplateFile
.text:00574973 push 80h ; dwFlagsAndAttributes
.text:00574978 push 2 ; dwCreationDisposition
.text:0057497A push 0 ; lpSecurityAttributes
.text:0057497C push 0 ; dwShareMode
.text:0057497E push 40000000h ; dwDesiredAccess
.text:00574983 push edx ; lpFileName
.text:00574984 call ds:CreateFileA
.text:0057498A mov esi, eax
.text:0057498C cmp esi, 0FFFFFFFFh
.text:0057498F jz short loc_5749C8
.text:00574991 call ds:GetCurrentThreadId
.text:00574997 push 0
.text:00574999 push 0
.text:0057499B mov [ebp+var_1C], eax
.text:0057499E lea eax, [ebp+var_1C]
.text:005749A1 push eax
.text:005749A2 push 0
.text:005749A4 push esi
.text:005749A5 mov [ebp+var_18], ebx
.text:005749A8 mov [ebp+var_14], 1
.text:005749AF call ds:__imp_GetCurrentProcessId
.text:005749B5 push eax
.text:005749B6 call ds:GetCurrentProcess
.text:005749BC push eax
.text:005749BD call edi
.text:005749BF push esi ; hObject
.text:005749C0 call ds:CloseHandle
.text:005749C6 jmp short loc_574A02
Thats from game.exe. It turns out game.exe does it's own minidump. My minidump was triggering after theirs so what I was seeing in my stack trace was a trace of their dump process. I found a dmp file in the game''s installation directory and once I loaded my symbols into it, it showed the correct output I was after.
You are doing just fine. When you open the minidump you generated, after you load the symbols, do
.ecxr
first to set context to what you saved in ExceptionInformation parameter to MiniDumpWriteDump(). Then you will have a legit stack trace.
We use a similar dump generation mechanism at the place where I work.
there are some future gotchas though. You want to check whether your dump catch mechanism is triggered on things like an abort() call.
For that, check out _set_invalid_parameter_handler() and signal(SIGABRT, ...).
I figured it out. Basically game.exe had its own MiniDumpWriteDump code that was triggering before my code. So the stack trace I was getting wasn't a trace of the error, it was a trace of game.exe doing its own MiniDump. I put more details up in the original post.
Thanks!
I would like to attach to a running process using WinDbg, and modify a certain function's code to simply return on invocation (for educational purposes).
I have used the following commands:
uf dll!name
This gives me a disassembly of the function.
I have picked a specific address at a certain location and modified it to ret:
ew addr c3
This crashes every time, what am i doing wrong?
You need to make sure you do the appropriate clean up so the stack is left in a proper state. Depending on the calling convention the method usually pushes stuff on the stack as part of the prologue. This must be undone as part of the epilogue.
Here's an example of changing a JIT compiled method using WinDbg.
The code:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Message();
Console.ReadLine();
Message();
Console.WriteLine("done");
}
private static void Message()
{
Console.WriteLine("message");
}
}
}
I compiled this as Debug to prevent the compiler from inlining the calls to Message.
Then I ran the executable and attached the debugger at the call to ReadLine.
For managed code I need to use SOS.dll to locate the JIT compiled code. So I loaded SOS and found the address for the code as follows.
0:004> .loadby sos clr
0:004> !name2ee *!ConsoleApplication1.Program
Module: 04a11000
Assembly: mscorlib.dll
--------------------------------------
Module: 001b2e94
Assembly: ConsoleApplication1.exe
Token: 02000002
MethodTable: 001b37b4
EEClass: 001b125c
Name: ConsoleApplication1.Program
0:004> !dumpmt -md 001b37b4
EEClass: 001b125c
Module: 001b2e94
Name: ConsoleApplication1.Program
mdToken: 02000002
File: c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
BaseSize: 0xc
ComponentSize: 0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDe JIT Name
04d14960 04a16728 PreJIT System.Object.ToString()
04d08790 04a16730 PreJIT System.Object.Equals(System.Object)
04d08360 04a16750 PreJIT System.Object.GetHashCode()
04d016f0 04a16764 PreJIT System.Object.Finalize()
001bc019 001b37ac NONE ConsoleApplication1.Program..ctor()
002a0050 001b3794 JIT ConsoleApplication1.Program.Main(System.String[])
002a00a8 001b37a0 JIT ConsoleApplication1.Program.Message()
0:004> !u 001b37a0
Normal JIT generated code
ConsoleApplication1.Program.Message()
Begin 002a00a8, size 21
*** WARNING: Unable to verify checksum for c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
c:\temp\ConsoleApplication1\ConsoleApplication1\Program.cs # 20:
002a00a8 55 push ebp <-- prologue
002a00a9 8bec mov ebp,esp
002a00ab 833d60311b0000 cmp dword ptr ds:[1B3160h],0 <-- start of method
002a00b2 7405 je ConsoleApplication1!ConsoleApplication1.Program.Message()+0x11 (002a00b9)
002a00b4 e8fb6ff570 call clr!JIT_DbgIsJustMyCode (711f70b4)
002a00b9 90 nop
c:\temp\ConsoleApplication1\ConsoleApplication1\Program.cs # 21:
002a00ba 8b0d34217403 mov ecx,dword ptr ds:[3742134h] ("message")
002a00c0 e82bd3ad04 call mscorlib_ni!System.Console.WriteLine(System.String) (04d7d3f0)
002a00c5 90 nop
c:\temp\ConsoleApplication1\ConsoleApplication1\Program.cs # 22:
002a00c6 90 nop
002a00c7 5d pop ebp <-- epilogue
002a00c8 c3 ret
Then I opened the Memory window and pointed it to 002a00ab which is the first part of the actual method body of Message and changed the two opcodes to 5d and c3 for pop edb and ret respectively. If I skipped the pop edb part the stack would be messed up and I would get an exception.
I hit Go and the application continued without printing "message" a second time.