Discussion:
w32dasm
(too old to reply)
Skybuck Flying
2005-08-11 18:42:21 UTC
Permalink
Hi,
I would like to change some executables workings.
1. Disassemble it with w32dasm and then somehow re-assemble it.
Which tool is able to re-assemble/link w32dasm output or is this
impossible
?
2. Dissassemble it with w32dasm then write some patch to change the
executable.
I want to add extra code to the executable. So I think this would require
playing around
with microsoft's portable executable formaat (coff) and change many
headers,
like code size,
,checksum etc which all seems lot's of work to do.
The last possibilitie could be dll inserting into of modifieing the
executable...
But modifieing executables seems coolest and most handy/flexible.
Are there any tools which can help me ? ;) Is there anybody in this
newsgroup with experience of completely modifieing executables ? ;)
Bye,
Skybuck.
I would like to change some executables workings.
Surf back over to the Delphi groups and ask me there. I have done
extensive work with this with a DLL that patches the code in memory once
loaded. No problem with finding places to store your code: You make the
host application call your DLL's code.
Ok, do you have some delphi code to get me started and try modifieing some
simple delphi console programs ? ;)

If you have much experience writing binary instructions/asm etc... I might
contact you later in case I need some help.

I think I can code in binary instructions etc... the only thing which I
might not know is if it is possible to reserve some space to copy something
into.

For example... I need to copy a buffer from an application into a new buffer
so that I can modify it and later pass it back replacing the original buffer
etc...

Can I simply use something like:

db 10000

Or do I have to allocate memory somehow ? ;)

Bye,
Skybuck.
Nicholas Sherlock
2005-08-12 05:35:46 UTC
Permalink
Post by Skybuck Flying
Ok, do you have some delphi code to get me started and try modifieing some
simple delphi console programs ? ;)
You'll be building a DLL which will contain the patching and hooking
code, and you'll want an .exe which will start up the target application
and inject your DLL into it. The meat of the .exe code is something like
this:

var
StartUpInfo: TStartUpInfo;
ProcInfo: Process_Information;
errno: integer;
msg: pchar;
begin
FillChar(StartUpInfo, SizeOf(StartUpInfo), 0);
StartUpInfo.cb := SizeOf(StartUpInfo);
if not CreateProcessex(nil,
'C:\targetapp.exe',
nil, nil, False, 0, nil, nil,
StartUpInfo, ProcInfo, 'c:\mydll.dll') then begin
ErrNo := GetLastError;
Msg := AllocMem(4096);
try
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, ErrNo,
0, Msg, 4096, nil);
showmessage('Create Process Error #' + IntToStr(ErrNo) + ': ' +
string(Msg));
finally
FreeMem(Msg);
end;
end;
h := procinfo.hprocess;
end;

Your DLL's main procedure (begin...end.) will be executed when the
application starts (You can immediately create and show forms,
everything!). The way I like to add code to already existing code
depends on the target application. Do you want to tack code onto the
beginning or end of a C++ object's methods, or add code to the middle of
an existing code block?

If trying to add code to the middle of an existing code block, you can
use something like this (Untested: Had to rip out of my application):

var patches: tobjectlist;

const retn = $C3;
nop = $90;
ipush = $68;
iret = $C3;
icall = $E8;
ipusheax = $50;
type
thookprocedure = procedure(injectpoint: pointer; eax, ecx, edx, esi:
longword);

tjumpstruct = packed record
push1: byte;
oldaddress: pointer;
push2: byte;
newaddress: pointer;
ret: byte;
end;

TPatch = class
public
oldaddress, newaddress: pointer;
handler: thookprocedure;
buf: string;

restorepoint: pointer;
restorebuf: string;

procedure patch; virtual;
procedure patchrestorer; virtual;

procedure backup; virtual;
procedure restore; virtual;
procedure restorerestorepoint; virtual;
end;

procedure patchgeneric(injectpoint, restorepoint: pointer; handler:
thookprocedure);

implementation

procedure dohook(esi, edx, ecx: longword; ainjection: pointer; eax:
longword); stdcall;
var t1: integer;
myfunc: thookprocedure;
begin
for t1 := 0 to patches.count - 1 do
if tpatch(patches[t1]).oldaddress = ainjection then begin
myfunc := tpatch(patches[t1]).handler;
myfunc(ainjection, eax, ecx, edx, esi); // call registered handler
tpatch(patches[t1]).restore; // return the original code at
injection site
tpatch(patches[t1]).patchrestorer; // install the restorer hook
exit;
end;
showmessage('Hook not found!');
end;

procedure dorestore(ainjection: pointer);
var t1: integer;
begin
for t1 := 0 to patches.count - 1 do
if tpatch(patches[t1]).restorepoint = ainjection then begin
tpatch(patches[t1]).restorerestorepoint; // return original
code at restore point
tpatch(patches[t1]).patch; // install injection hook
exit;
end;
end;

procedure resmain;
asm
pushad
mov eax,[esp+$20] // injection point address
call dorestore
popad
ret
end;

procedure injmain;
asm
pushad
push eax
mov eax,[esp+$24] // injection point address
push eax
push ecx
push edx
push esi
call dohook
popad
ret
end;

procedure tpatch.patch;
var
oldprotect: cardinal;
j: tjumpstruct;
jumplength: integer;
begin
j.push1 := ipush;
j.oldaddress := oldaddress;
j.push2 := ipush;
j.newaddress := newaddress;
j.ret := iret;

jumplength := sizeof(j);
VirtualProtect(oldaddress, jumplength, PAGE_EXECUTE_READWRITE,
oldprotect);
Move(j, oldaddress^, sizeof(j));
end;

procedure tpatch.patchrestorer;
var
oldprotect: cardinal;
j: tjumpstruct;
jumplength: integer;
begin
j.push1 := ipush;
j.oldaddress := restorepoint;
j.push2 := ipush;
j.newaddress := @resmain;
j.ret := iret;

jumplength := sizeof(j);
VirtualProtect(restorepoint, jumplength, PAGE_EXECUTE_READWRITE,
oldprotect);
Move(j, restorepoint^, sizeof(j));
end;

procedure tpatch.backup;
var jumplength: integer;
begin
jumplength := sizeof(tjumpstruct);

setlength(buf, jumplength);
move(oldaddress^, buf[1], jumplength);

setlength(restorebuf, jumplength);
move(restorepoint^, restorebuf[1], jumplength);
end;

procedure tpatch.restore;
begin
move(buf[1], oldaddress^, length(buf)); // move old code back
end;

procedure tpatch.restorerestorepoint;
begin
move(restorebuf[1], restorepoint^, length(restorebuf)); // move old
code back
end;

procedure patchgeneric(injectpoint, restorepoint: pointer; handler:
thookprocedure);
var patch: tpatch;
begin
patch := tpatch.Create;

patch.oldaddress := injectpoint;
patch.newaddress := @injmain;
patch.restorepoint := restorepoint;
patch.handler := handler;

patches.add(patch);
patch.backup;
patch.patch;
end;

Usage: This patching method requires the address of the site where you
want to inject your code ("Injectpoint") and a restore point at least 11
bytes later on in the routine ("Restorepoint"). Your handler will be
called with the contents of some registers.

Algorithm: The code writes some code at the injectpoint which calls
"Injmain", this routine calls your handler, copies the code that used to
be at the injection site back, then returns control back to the target
application. When the target appication reaches the restorepoint, it
reinstalls the new code at the injectpoint and returns the original code
back to the restorepoint. Complex, but it works. Who knows what will
happen if your procedure is recursive :). I shudder to consider what
might happen if the target application is multithreaded.

If you are patching a C++ object's method, then you can do a much
cleaner version which allows you to access and modifiy all of the
parameters of the method and allows you to allow or deny the original
method running.

You should add exception handlers to the procedures I've posted so that
Delphi exceptions don't filter through to the host application: They
don't like that :).
Post by Skybuck Flying
For example... I need to copy a buffer from an application into a new buffer
so that I can modify it and later pass it back replacing the original buffer
etc...
What sort of buffer?
Post by Skybuck Flying
db 10000
Or do I have to allocate memory somehow ? ;)
Depends on what you are talking about and what your target is.

Cheers,
Nicholas Sherlock
Skybuck Flying
2005-08-14 17:51:48 UTC
Permalink
Hi Nicholas,

Just wanted to write to you that I am very busy at the moment developing
some other programs etc...

Though I look forward to investigating this example etc... so as soon as I
am done with those other proggies I will get back to you on this... I'll
probably have some questions etc... I have no idea how long it's going to
take before the other programs are done... might be a few days, might be a
few weeks, might even be two months max ;)

Since this modifieing of executables is pretty complex/new stuff for me I
have to postpone it until I can give it my full attention :D So all I can
say is, stay tuned to this newsgroup :D

Bye,
Skybuck.
Nicholas Sherlock
2005-08-14 22:40:36 UTC
Permalink
Post by Skybuck Flying
Since this modifieing of executables is pretty complex/new stuff for me I
have to postpone it until I can give it my full attention :D So all I can
say is, stay tuned to this newsgroup :D
No problem. It's all fun stuff and a very interesting challenge when you
delve into it. Only suggestion: Get the disassembler IDA Pro. Nothing
beats it. You can comment, rename variables and improve the disassembly
while you work on it. I've found it the perfect tool when translating
routines from assembly to pascal, even though I have _never_ written any
assembly before (Except for those few push/pops in that hook handler :)).

Cheers,
Nicholas Sherlock
Skybuck Flying
2005-08-15 08:44:52 UTC
Permalink
Post by Nicholas Sherlock
Post by Skybuck Flying
Since this modifieing of executables is pretty complex/new stuff for me I
have to postpone it until I can give it my full attention :D So all I can
say is, stay tuned to this newsgroup :D
No problem. It's all fun stuff and a very interesting challenge when you
delve into it. Only suggestion: Get the disassembler IDA Pro. Nothing
beats it. You can comment, rename variables and improve the disassembly
while you work on it. I've found it the perfect tool when translating
routines from assembly to pascal, even though I have _never_ written any
assembly before (Except for those few push/pops in that hook handler :)).
Ok I have given IDA Pro a try and so far it seems just another disassembler
?

Disassembling is not the problem ;) Modifieing is the problem :D

For example I have this simple line of code which I would like to change

from:

CODE:00408590 mov edx, 3E8h

to:

CODE:00408590 mov edx, 3F2h

(decimal 1000 to 1010)

The help file says to select submenu "edit|patch program"

But I don't have this menu item "patch program" ???

I could simply use a hex editor and change the program just like that... why
can't these assemblers do that ???
(everything is read only... can't change a thing ! pretty retarded ! ;) )

So far the only success I had into modifieing the executable was by running
it, breaking point this line and then stepping over it and then I had to
change the contents of the edx register from christ's sake ! :Ds
sttuuppiiddd.

Sigh.

Thx anyway, this disassembler does seem to have other nice features like
displaying where gaps are inside the executable ??? does this mean those
gaps can be used to place new/extra binary code ?

Bye,
Skybuck.
Nicholas Sherlock
2005-08-15 09:57:58 UTC
Permalink
Post by Skybuck Flying
I could simply use a hex editor and change the program just like that... why
can't these assemblers do that ???
(everything is read only... can't change a thing ! pretty retarded ! ;) )
Yeah, that is pretty retarded. I don't know why they don't include an
assemble command function.
Post by Skybuck Flying
So far the only success I had into modifieing the executable was by running
it, breaking point this line and then stepping over it and then I had to
change the contents of the edx register from christ's sake ! :Ds
sttuuppiiddd.
If you use view->hex editor, you can find the hex address of the byte(s)
you want to change. Then (At runtime from your DLL):

var pb:pbyte;
oldprotect:cardinal;

pb := ptr($4E9DBA);
VirtualProtect(pb, 1, PAGE_EXECUTE_READWRITE, oldprotect);
pb^ := $EB; // Replace the instruction at $4E9DBA with an unconditional jump
Post by Skybuck Flying
Thx anyway, this disassembler does seem to have other nice features like
displaying where gaps are inside the executable ??? does this mean those
gaps can be used to place new/extra binary code ?
Depends on the gap. Depending on the segment/section/whatever, it may
simply be spaced reserved for storing data by the executable. AFAIK, you
can just append code to the end of the .exe, but I've never tried it:
It's easier just to jump to code in your DLL.

Cheers,
Nicholas Sherlock
Skybuck Flying
2005-08-15 12:55:11 UTC
Permalink
Post by Nicholas Sherlock
Post by Skybuck Flying
I could simply use a hex editor and change the program just like that... why
can't these assemblers do that ???
(everything is read only... can't change a thing ! pretty retarded ! ;) )
Yeah, that is pretty retarded. I don't know why they don't include an
assemble command function.
Post by Skybuck Flying
So far the only success I had into modifieing the executable was by running
it, breaking point this line and then stepping over it and then I had to
change the contents of the edx register from christ's sake ! :Ds
sttuuppiiddd.
If you use view->hex editor, you can find the hex address of the byte(s)
var pb:pbyte;
oldprotect:cardinal;
pb := ptr($4E9DBA);
VirtualProtect(pb, 1, PAGE_EXECUTE_READWRITE, oldprotect);
pb^ := $EB; // Replace the instruction at $4E9DBA with an unconditional jump
Post by Skybuck Flying
Thx anyway, this disassembler does seem to have other nice features like
displaying where gaps are inside the executable ??? does this mean those
gaps can be used to place new/extra binary code ?
Depends on the gap. Depending on the segment/section/whatever, it may
simply be spaced reserved for storing data by the executable. AFAIK, you
I don't think that will work... even if it gets loaded into memory it
doesn't have any execute permissions ? ;)

Bye,
Skybuck ;)
Post by Nicholas Sherlock
It's easier just to jump to code in your DLL.
Cheers,
Nicholas Sherlock
Nicholas Sherlock
2005-08-16 01:20:02 UTC
Permalink
Post by Skybuck Flying
I don't think that will work... even if it gets loaded into memory it
doesn't have any execute permissions ? ;)
Probably, why not just use your DLL? :). Then windows takes care of
everything.

Cheers,
Nicholas Sherlock

Skybuck Flying
2005-08-15 07:34:36 UTC
Permalink
How much does your technique differ from this technique:

http://www.devx.com/Intel/Article/21023/2046

I think your technique uses automatic insertion and restoration of the
injection point/code ?

Bye,
Skybuck ;)
Post by Nicholas Sherlock
Post by Skybuck Flying
Ok, do you have some delphi code to get me started and try modifieing some
simple delphi console programs ? ;)
You'll be building a DLL which will contain the patching and hooking
code, and you'll want an .exe which will start up the target application
and inject your DLL into it. The meat of the .exe code is something like
var
StartUpInfo: TStartUpInfo;
ProcInfo: Process_Information;
errno: integer;
msg: pchar;
begin
FillChar(StartUpInfo, SizeOf(StartUpInfo), 0);
StartUpInfo.cb := SizeOf(StartUpInfo);
if not CreateProcessex(nil,
'C:\targetapp.exe',
nil, nil, False, 0, nil, nil,
StartUpInfo, ProcInfo, 'c:\mydll.dll') then begin
ErrNo := GetLastError;
Msg := AllocMem(4096);
try
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, ErrNo,
0, Msg, 4096, nil);
showmessage('Create Process Error #' + IntToStr(ErrNo) + ': ' +
string(Msg));
finally
FreeMem(Msg);
end;
end;
h := procinfo.hprocess;
end;
Your DLL's main procedure (begin...end.) will be executed when the
application starts (You can immediately create and show forms,
everything!). The way I like to add code to already existing code
depends on the target application. Do you want to tack code onto the
beginning or end of a C++ object's methods, or add code to the middle of
an existing code block?
If trying to add code to the middle of an existing code block, you can
var patches: tobjectlist;
const retn = $C3;
nop = $90;
ipush = $68;
iret = $C3;
icall = $E8;
ipusheax = $50;
type
longword);
tjumpstruct = packed record
push1: byte;
oldaddress: pointer;
push2: byte;
newaddress: pointer;
ret: byte;
end;
TPatch = class
public
oldaddress, newaddress: pointer;
handler: thookprocedure;
buf: string;
restorepoint: pointer;
restorebuf: string;
procedure patch; virtual;
procedure patchrestorer; virtual;
procedure backup; virtual;
procedure restore; virtual;
procedure restorerestorepoint; virtual;
end;
thookprocedure);
implementation
longword); stdcall;
var t1: integer;
myfunc: thookprocedure;
begin
for t1 := 0 to patches.count - 1 do
if tpatch(patches[t1]).oldaddress = ainjection then begin
myfunc := tpatch(patches[t1]).handler;
myfunc(ainjection, eax, ecx, edx, esi); // call registered handler
tpatch(patches[t1]).restore; // return the original code at
injection site
tpatch(patches[t1]).patchrestorer; // install the restorer hook
exit;
end;
showmessage('Hook not found!');
end;
procedure dorestore(ainjection: pointer);
var t1: integer;
begin
for t1 := 0 to patches.count - 1 do
if tpatch(patches[t1]).restorepoint = ainjection then begin
tpatch(patches[t1]).restorerestorepoint; // return original
code at restore point
tpatch(patches[t1]).patch; // install injection hook
exit;
end;
end;
procedure resmain;
asm
pushad
mov eax,[esp+$20] // injection point address
call dorestore
popad
ret
end;
procedure injmain;
asm
pushad
push eax
mov eax,[esp+$24] // injection point address
push eax
push ecx
push edx
push esi
call dohook
popad
ret
end;
procedure tpatch.patch;
var
oldprotect: cardinal;
j: tjumpstruct;
jumplength: integer;
begin
j.push1 := ipush;
j.oldaddress := oldaddress;
j.push2 := ipush;
j.newaddress := newaddress;
j.ret := iret;
jumplength := sizeof(j);
VirtualProtect(oldaddress, jumplength, PAGE_EXECUTE_READWRITE,
oldprotect);
Move(j, oldaddress^, sizeof(j));
end;
procedure tpatch.patchrestorer;
var
oldprotect: cardinal;
j: tjumpstruct;
jumplength: integer;
begin
j.push1 := ipush;
j.oldaddress := restorepoint;
j.push2 := ipush;
j.ret := iret;
jumplength := sizeof(j);
VirtualProtect(restorepoint, jumplength, PAGE_EXECUTE_READWRITE,
oldprotect);
Move(j, restorepoint^, sizeof(j));
end;
procedure tpatch.backup;
var jumplength: integer;
begin
jumplength := sizeof(tjumpstruct);
setlength(buf, jumplength);
move(oldaddress^, buf[1], jumplength);
setlength(restorebuf, jumplength);
move(restorepoint^, restorebuf[1], jumplength);
end;
procedure tpatch.restore;
begin
move(buf[1], oldaddress^, length(buf)); // move old code back
end;
procedure tpatch.restorerestorepoint;
begin
move(restorebuf[1], restorepoint^, length(restorebuf)); // move old
code back
end;
thookprocedure);
var patch: tpatch;
begin
patch := tpatch.Create;
patch.oldaddress := injectpoint;
patch.restorepoint := restorepoint;
patch.handler := handler;
patches.add(patch);
patch.backup;
patch.patch;
end;
Usage: This patching method requires the address of the site where you
want to inject your code ("Injectpoint") and a restore point at least 11
bytes later on in the routine ("Restorepoint"). Your handler will be
called with the contents of some registers.
Algorithm: The code writes some code at the injectpoint which calls
"Injmain", this routine calls your handler, copies the code that used to
be at the injection site back, then returns control back to the target
application. When the target appication reaches the restorepoint, it
reinstalls the new code at the injectpoint and returns the original code
back to the restorepoint. Complex, but it works. Who knows what will
happen if your procedure is recursive :). I shudder to consider what
might happen if the target application is multithreaded.
If you are patching a C++ object's method, then you can do a much
cleaner version which allows you to access and modifiy all of the
parameters of the method and allows you to allow or deny the original
method running.
You should add exception handlers to the procedures I've posted so that
Delphi exceptions don't filter through to the host application: They
don't like that :).
Post by Skybuck Flying
For example... I need to copy a buffer from an application into a new buffer
so that I can modify it and later pass it back replacing the original buffer
etc...
What sort of buffer?
Post by Skybuck Flying
db 10000
Or do I have to allocate memory somehow ? ;)
Depends on what you are talking about and what your target is.
Cheers,
Nicholas Sherlock
Nicholas Sherlock
2005-08-15 10:00:35 UTC
Permalink
Post by Skybuck Flying
http://www.devx.com/Intel/Article/21023/2046
I think your technique uses automatic insertion and restoration of the
injection point/code ?
Doesn't sound much like my method. My method copies the code that was
overwritten by the patch back to its "Original environment", so it
doesn't have to worry about jumps that existed inside this code becoming
invalid, or about cutting an instruction in half. The only requirement
is that there is also a restorer later on which is always executed and
which repatches the code at the primary injection sited.

Cheers,
Nicholas Sherlock
Loading...