I wrote a subroutine to be used as a Trap call via Trap x26. My code for my subroutine is at address x3300. I cannot figure out how to jump from x26 to my actual instructions for the subroutine at x3300, since the gap is greater than JSR's PC offset parameter allows. I know I could add some code in near x26 to make it possible to jump all the way to x3300, but I don't think that's how I am supposed to do it. I think I'm missing something with understanding traps in general.
Here's my understanding/confusion of traps: So from x0000 - X00FF is the trap vector table. For example, if you call TRAP x20, then the PC goes to x20 and continues execution with the instruction at x20. (Please let me know if this is incorrect!) At this point I am confused because at the address x20 in the LC-3 is a BRZ x0021 command, which takes the PC to x21. At x21, there is a BRZ x52command. When this branch gets executed to go to x52 plus the PC, the command there is TRAP x00. Most of the Trap 20's commands seem to go to these (what look like) nonsense trap commands. After the trap x00 is executed, the program goes to xFD79. This is really confusing me since at x00 in memory, there is just another TRAP x00. To me, it seems like the program should go to x00 instead of xFD79.
Can someone help explain this to me please? What exactly is going on when a trap is called? I thought it just went to another address in memory where the actual code for the instruction was and executed that, but what I have seen doesn't reflect that. Any help is greatly appreciated as this is preventing me from completing a school project right now.
Thanks!
"So from x0000 - X00FF is the trap vector table. For example, if you call TRAP x20, then the PC goes to x20 and continues execution with the instruction at x20. (Please let me know if this is incorrect!)"
This is correct, however the next sentence...
"At this point I am confused because at the address x20 in the LC-3 is a BRZ x0021 command, which takes the PC to x21"
The command you see which looks like a BRz is not, in fact, an instruction. It is an address! x0400 would be a fairly useless command - it the PC offset is zero, so it just goes to the next line. If you interpret it as an address instead, and go to that address as part of the trap call, you will find the rest of the trap instructions.
Related
Is there a SPARC equivalent to x86's single step mode? What I want is to stop execution after every instruction and move control flow to a trap handler or something similar.
I thought of using the ta instruction in the delayed execution slot but this would not work when the previous instruction is a branching instruction with the annul bit set.
Sparc lacks a single step bit in PSR, so it's harder to single step. But I've used a trick to help get closer. Set TPC to the address of the instruction you want to single step, and set TNPC to an address someplace else where you've placed a trap instruction. When you execute the retry instruction to get back to the process context, it will single step the one instruction you want, then it will next execute the trap instruction which will bring you right back to the kernel, where you can do whatever you want. (n.b this is for sparc64, not sure about sparc32). This is a nice trick because you don't have modify existing instructions in the user's address space. This was important to me since I was single stepping instructions in the kernel.
Another idea I had, but never tried, was to simply set TNPC to an illegal address. Then after the instruction at TPC was executed, you'd get an automatic trap back into the kernel. And since the trap handling code knows that the process is being single stepped, there would be no confusion over a "real" illegal address trap.
I used JSR and RET to jump to a subroutine and jump back to the main function. However, every time when the PC is on the address of RET, it stops there and never moves. Is there any possible reason for this problem? I did not use any subroutine inside my first subroutine, but I do use Branches. SO, I think my R7 does not change in the subroutine.
Are you using any TRAPs? TRAP modifies R7 also.
I'm working on some shellcoding, and have this weird result on my Windows VM. The idea is, starting from Zero, carve out some value. In this case, I need that the value is equals to: 0x50505353
(gdb) print /x 0 - 0x38383536 - 0x77777777
$1 = 0x50505353
In Python, GDB, OSX, Linux and everything else, this operation works as expected. On the Windows VM, when I perform the PUSH on OllyDBG or Immunity the result is: 0x52535051
So the question is, WHY? What I'm missing here?
This is the operation done in ASM:
AND EAX,65656565
AND EAX,1A1A1A1A
SUB EAX,38383536
SUB EAX,77777777
PUSH EAX
The first couple of AND transform EAX = 0x00000000. Then I can subtract from that. Just to be clear, I cannot use XOR on this test.
This is because you are not subtracting 0x38383536, you are subtracting 0x36353838, which gives the result you stated.
I just found the problem. When I do the calculations outside the Debugger, forgot the small detail that in order to use them in the shellcode, I should use the same values in reverse Endian Order.
Mental note: Always remember to check the order that you are working.
Thanks to all.
To be clear, are you saying error happens on the gdb command line as well as in your windows VM program? If gdb is giving rubbish then something is wrong with the VM.
Do you have gdb or another debugger working on the Windows VM? I'm a little confused about your runtime environment where you are seeing the error
If you have gdb where the error is occurring then here is how to debug.
If it is the program only then use stepi and info regs to see what is going on. The value of $eax before that last subtraction is likely the one of interest but check each instruction. If $eax has the correct value at the push then look around $sp in memory for the value. If it is still correct then follow the return from the function and look for the corresponding pop or stack read and check the value there. Perhaps the stack is getting corrupted before you actually print/use the value?
I am currently debugging some assembly code using GDB and am stuck on the following problem. Somehow or other, I've ended up at a bogus instruction address, probably because either I called a bogus function pointer, or I mangled the return address on the parent stack frame.
GDB is fantastic and stops the program exactly when it detects this has happened. However, what it doesn't tell me is the instruction address that sent me to this bogus address. So now I am stuck. I know that I am now at a bogus address, but I have no way of knowing how I got here. What I think I need is a list of the last n values that $rip has taken on. But I cannot find any way of doing that in GDB's documentation and am pretty sure it is not possible.
So I would appreciate it if anyone else had any great tips on low-level debugging they could share. Thanks!
-Patrick
I think GDB's trace might helps
https://sourceware.org/gdb/onlinedocs/gdb/Tracepoints.html
When your code crash, the trap is raised and the instruction pointer jump to the trap table, the jump depends on the trap raised.
You want to determine which instruction causes this trap, so you can execute the command backtrace (bt) to show the latest exectuted functions before the jump to the trap table. When you identify the function, execute step by step to idenfy the instruction which causes the error.
If you are using a target with gdb in remote mode, you need to give gdb a strong symbol table to allow the awareness of the whole code symbols.
Currently i'm playing with the windows/WOW64 trick known as "the heaven's gate", which, as some of you will probably know, allows us to enter x64 mode even though in a x86 program (i was so amazed when i tested it and it worked!) But i know it is not supported on all Windows versions, so my code (because there is a code) uses seh, it looks like this:
start:
use32
;; setup seh...
call $33:.64bits_code ; specify 0x33 segment, it's that easy
;; success in x64 mode, quit seh...
jmp .exit
.64bits_code:
use64
;; ...
use32
retf
.seh_handler:
use32
;; ...
xor eax,eax ; EXCEPTION_CONTINUE_EXECUTION
ret
.32bits_code:
; we have been called by a far call (well, indirectly, routed by a seh handler)
; HERE IS THE PROBLEM => Should i use a retf since cs and eip are on the stack,
; or the exception has been triggered before pushing them???
; "retf" or "jmp .exit"?
.exit:
xor eax,eax
push eax
call [ExitProcess]
I know a simple "jmp .exit" would do the trick, but i'm terribly curious about it
When the OS gets an interrupt or a fault happens, it expects that no matter what the user code was up to, the CPU has saved the required state on the kernel stack so that an IRET will invisibly resume whatever it was doing.
Note that there is no "magic" involved in that state on the kernel stack. "Continuing execution" only means restoring saved values of rflags, cs:rip and ss:rsp and running the code that cs:rip ends up pointing to.
That means that without involving SEH specifically, just thinking about any kind of exception happening during a far call, there are really only two cases to consider:
The exception happens "before" the jump: nothing has been pushed, the state on the kernel stack says we should resume by restarting the call instruction.
The exception happens "after" the jump: cs:eip have been pushed, rip points somewhere at or after the .64bits_code label, and that saved state says that to resume we should jump to the 64-bit code.
If the CPU allowed a far call to be interrupted "in the middle", there would be no possible value of cs:rip that produces a consistent result when the OS continues execution. For example, if the far call's return address was pushed before the exception happened but the saved cs:rip points to the far call instruction, you'll end up with two copies of the return address on the stack and all hell breaks loose.
Now, to actually answer your question: it depends on the value of rIP that the OS tells you the exception happened on. If it points to the 64-bit code you must have cs:eip on the stack, if it points to the 32-bit code you can safely assume it has not been pushed yet.