Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Dec 14th, 2005, 9:14 PM   #1
para
Programmer
 
Join Date: Dec 2005
Posts: 65
Rep Power: 3 para is on a distinguished road
C/asm jmp calculation

Ok this is mostly C but my question is really based around ASM techniques so I decided it would be best to post it here.

I'm working on a small project that will overwrite parts of the machine code in the current process space. My goal is to always redirect the function a() to function b(). Not a very practical application but it's something to learn from
Anyhow, here's the general code:

byte patch[] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };

void a() {
	printf("a() called\n");
}

void b() {
	printf("b() called\n");
}

int main() {
	void* aptr = a;
	printf("a: %p\n", a);
	memcpy(patch+1, &aptr, 4);

	printf("patching..\n");
	memcpy(a, patch, sizeof(patch));
	printf("patched\n");

	printf("calling a()...\n");
	a();

	return 0;
}

I cut out the part of the code that makes the memory space writable, so assume the memcpy() is legal. The array is a 5 byte jmp function I compiled and grabbed out of a disassembly. 0xe9 is the jmp, then 4 0x00's which is updated in the first memcpy() in main(). So everything works until I try to call a() at the bottom of main(), where it crashes. Is this pointer I copied into the function code valid? Why is it crashing?
para is offline   Reply With Quote
Old Dec 15th, 2005, 6:03 AM   #2
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Variable 'a' is not declared so: void* aptr = a; will not point to somewhere undefined.
In your case, memcpy(a, patch, sizeof(patch)); makes it crash.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Dec 15th, 2005, 6:09 AM   #3
para
Programmer
 
Join Date: Dec 2005
Posts: 65
Rep Power: 3 para is on a distinguished road
Quote:
Originally Posted by nnxion
Variable 'a' is not declared so: void* aptr = a; will not point to somewhere undefined.
In your case, memcpy(a, patch, sizeof(patch)); makes it crash.
Actually I think that's C99; (void*)&a would work too, it's a pointer to the a function.
The code ends up being in the array:
0xe9 0x04 0x03 0x02 0x01
assuming the address for the function a is 0x01020304 (little endian machine).
para is offline   Reply With Quote
Old Dec 15th, 2005, 6:34 AM   #4
lectricpharaoh
Caffeinated Neural Net
 
lectricpharaoh's Avatar
 
Join Date: Jun 2005
Location: Dry west coast of Canada
Posts: 1,031
Rep Power: 5 lectricpharaoh will become famous soon enough
Quote:
Originally Posted by para
byte patch[] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };
 
void a() {
	printf("a() called\n");
}
 
void b() {
	printf("b() called\n");
}
 
int main() {
	void* aptr = a;
	printf("a: %p\n", a);
	memcpy(patch+1, &aptr, 4);
 
	printf("patching..\n");
	memcpy(a, patch, sizeof(patch));
	printf("patched\n");
 
	printf("calling a()...\n");
	a();
 
	return 0;
}
I think the two lines in red might be part of the problem. First you copy the address of a into elements 1 through 4 of the patch array, so it contains 0E9h followed by the address- fine. Then, in the second memcpy(), you copy five bytes from patch to a four-byte, constant value. Assuming you have indeed made the function's offset address value writable in the code segment, you're still trying to copy five bytes to a four-byte value (oops). Second, I'm not sure this would work even aside from that. The function's address is a constant value, and will likely be resolved at link time, with all references to the function being replaced by a constant value. You replace one instance, but not all the others. Get what I mean?

Why not try something like using double indirection to get at the memory pointed at by the function's offset, then changing the data there? Replace the function body with a RET instruction, or something. See if that works.

[edit] No need for double indirection, my bad. I need sleep. [/edit]
__________________
And once again, Probability proves itself willing to sneak into a back alley and service Drama as would a copper-piece harlot.
- Vaarsuvius, Order of the Stick

Last edited by lectricpharaoh; Dec 15th, 2005 at 6:49 AM.
lectricpharaoh is offline   Reply With Quote
Old Dec 15th, 2005, 6:53 AM   #5
lectricpharaoh
Caffeinated Neural Net
 
lectricpharaoh's Avatar
 
Join Date: Jun 2005
Location: Dry west coast of Canada
Posts: 1,031
Rep Power: 5 lectricpharaoh will become famous soon enough
I tried this code, but I got an access violation for trying to write to the memory. I dunno how to make it writable in Windows (using DevC++/MinGW, so it might be similar to how you do it with gcc under Linux, if you care to share).
#include <stdio.h>
#include <stdlib.h>
 
void manlyMan(void);
void neuter(void (*soonToBeEunuch)(void));
 
void manlyMan(void)
{
  puts("I am a manly man!");
}
 
 
void neuter(void (*soonToBeEunuch)(void))
{
  char *target = (char *)soonToBeEunuch;
  *target = 0xC3; // plain old RET (near)
}
 
 
int main(void)
{
  puts("---");
  manlyMan();
  puts("---");
  neuter(manlyMan);
  manlyMan();
  puts("---");
  system("pause");
  return 0;
}
__________________
And once again, Probability proves itself willing to sneak into a back alley and service Drama as would a copper-piece harlot.
- Vaarsuvius, Order of the Stick

Last edited by lectricpharaoh; Dec 15th, 2005 at 7:05 AM.
lectricpharaoh is offline   Reply With Quote
Old Dec 15th, 2005, 7:52 AM   #6
splyxx
Newbie
 
Join Date: Nov 2005
Posts: 4
Rep Power: 0 splyxx is on a distinguished road
> Then, in the second memcpy(), you copy five bytes from patch to a four-byte,
> constant value. Assuming you have indeed made the function's offset address value
> writable in the code segment, you're still trying to copy five bytes to a four-byte value
> (oops). [...]

What makes you think it is four bytes? He's changing the machine code of a() itself, not the symbol "a".

"&a" is the same as "a" - the address of some code. And he is patching that code.

void a() {
printf("a() called\n");

Assuming push ebp, mov ebp, esp, push string, call printf, add esp, 4, pop ebp, we have at least six instructions occupying (much) more than four bytes.


> byte patch[] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };

You should be using some form of "call" instruction because a jump will not save the return address. Also, my opcode reference says 0xe9 is a relative jump, but you need an indirect one. The code you use should be the same as the code generated for

void foo() { stuff }
...
void (*p)() = foo;
p();

Last edited by splyxx; Dec 15th, 2005 at 8:05 AM.
splyxx is offline   Reply With Quote
Old Dec 15th, 2005, 11:12 AM   #7
para
Programmer
 
Join Date: Dec 2005
Posts: 65
Rep Power: 3 para is on a distinguished road
Quote:
Originally Posted by splyxx
> byte patch[] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };

You should be using some form of "call" instruction because a jump will not save the return address. Also, my opcode reference says 0xe9 is a relative jump, but you need an indirect one. The code you use should be the same as the code generated for

void foo() { stuff }
...
void (*p)() = foo;
p();
My goal is similar to parts of the "Detours" library (GPL'ed so others can use it since Detours is "research only").
http://research.microsoft.com/sn/detours/

Anyhow, I don't want to overwrite the opcodes with a call because I don't want control to return to that function. The function that is jumped to by the function a() should be of the same type so and parameter accessing/returning will (hopefully) be compatible.

Quote:
Originally Posted by splyxx
Also, my opcode reference says 0xe9 is a relative jump
This certainly makes sense to me since I'm on a 64-bit machine (program compiled in 32-bit). Looking at the disassembly if I have two consecutively jmp opcodes to the same label, I get something like:
08048468 <a>:
 8048468:       e9 1a 00 00 00          jmp    8048487 <b>
 804846d:       e9 15 00 00 00          jmp    8048487 <b>

Evidently the address is relative so I must be using the wrong opcode.
Is there a chart somewhere on available opcodes and their binary representation? Google turns up very little, and I got this code from a objdump disassembly :\
para is offline   Reply With Quote
Old Dec 15th, 2005, 12:07 PM   #8
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Quote:
Originally Posted by para
My goal is similar to parts of the "Detours" library (GPL'ed so others can use it since Detours is "research only").
http://research.microsoft.com/sn/detours/
Hehe had to check it out, MS to GPL something, but indeed they didn't. It's a Microsoft Research Shared Source license agreement, which is kind of the same I think.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Dec 15th, 2005, 2:08 PM   #9
splyxx
Newbie
 
Join Date: Nov 2005
Posts: 4
Rep Power: 0 splyxx is on a distinguished road
Cool

> Is there a chart somewhere on available opcodes and their binary representation?

I sort of totally love OPCODES.HLP

http://www.google.de/search?hl=de&q=opcodes.hlp&spell=1

I use winhelp in Wine on Linux to access this file. Had to get a friend to send me a dll and I think some other Windows file to make it work though NASM has a ton of good docs as well, including an x86 reference:

http://nasm.sourceforge.net/doc/html/nasmdocb.html

(BTW, this will be my last post in this forum, but you can PM me if you run into more problems regarding this interesting project.)
splyxx is offline   Reply With Quote
Old Dec 15th, 2005, 2:29 PM   #10
para
Programmer
 
Join Date: Dec 2005
Posts: 65
Rep Power: 3 para is on a distinguished road
Quote:
Originally Posted by splyxx
> Is there a chart somewhere on available opcodes and their binary representation?

I sort of totally love OPCODES.HLP

http://www.google.de/search?hl=de&q=opcodes.hlp&spell=1

I use winhelp in Wine on Linux to access this file. Had to get a friend to send me a dll and I think some other Windows file to make it work though NASM has a ton of good docs as well, including an x86 reference:

http://nasm.sourceforge.net/doc/html/nasmdocb.html

(BTW, this will be my last post in this forum, but you can PM me if you run into more problems regarding this interesting project.)
Excellent, thanks a lot! I was in need of additional resources, so this is just perfect

As a follow up I was able to solve the issue with using a relative address like you said before. Copied the 4 byte offset to the target function which was calculated with (dest - (source + 5)).

Invoking the source() function now "redirects" to the dest() function as desired. Thanks everyone for your help.
para is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 11:41 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC