2

This is my Working Code

  DriftMul:=99;
  WriteProcessMemory(HandleWindow, ptr($4E709C), @DriftMul, 2, Write);

I want to Convert it without using a variable but it wont work Below is just an Example of what i want to do.

WriteProcessMemory(HandleWindow, ptr($4E709C),  ptr(99), 2, Write);

Does anyone know a way to make this work with using a variable??? I am able to program in a few languages and every language i use their is a way to to do this. The reason i want to do this is because i am gonna be making a big program that does alot of writing of different values and it will save me around 300+ lines. Below is an Example in c++ i was using.

WriteProcessMemory(hProcess, (void*)0x4E709C, (void*)(PBYTE)"\x20", 1, NULL);

Update: Solved it Im using 4 Procedures that i call depending on how many bytes i want to write.

procedure Wpm(Address: Cardinal; ChangeValues: Byte);
Begin
 WriteProcessMemory(HandleWindow, Pointer(Address), @ChangeValues, 1, Write);
End;
procedure Wpm2(Address: Cardinal; ChangeValues: Word);
Begin
 WriteProcessMemory(HandleWindow, Pointer(Address), @ChangeValues, 2, Write);
End;
procedure Wpm3(Address: Cardinal; ChangeValues: Word);
Begin
 WriteProcessMemory(HandleWindow, Pointer(Address), @ChangeValues, 3, Write);
End;
procedure Wpm4(Address: Cardinal; ChangeValues: Cardinal);
Begin
 WriteProcessMemory(HandleWindow, Pointer(Address), @ChangeValues, 4, Write);
End;

Example writes

 Wpm($477343,$EB);
 Wpm2($40A889,$37EB);
 Wpm3($416E34,$0086E9);

Pchar is the only method i found to compile without procedures, i dont want to use assci though.

WriteProcessMemory(HandleWindow, Pointer($449A17), PChar('90'), 1, Write);
Tprice88
  • 651
  • 2
  • 7
  • 18
  • "Why does the above code write 43 though??" You mean `$43`. Well, what's the ASCII code for `C`? And why do you use 'C3' when you only write a single byte? What's the point of the second byte? Why not use `'C'`? – David Heffernan Mar 29 '12 at 19:19
  • with my converter im getting 99 – Tprice88 Mar 29 '12 at 19:22
  • Can you explain where 99 comes from, where C3 comes from and what you are expecting? I must confess to being boggled that you would willingly obfuscate your code like this. – David Heffernan Mar 29 '12 at 19:23
  • i used this site http://easycalculation.com/ascii-hex.php – Tprice88 Mar 29 '12 at 19:30
  • And how do you come up with these particular values? – David Heffernan Mar 29 '12 at 19:33
  • It lets me compile with PChar('90') but i still cant think of way to forge the numbers i want, do you know another way?? – Tprice88 Mar 29 '12 at 19:36
  • Of course that code is writing $39 since that's the ASCII code for the digit `9`. Why don't you read my first comment above very carefully and see if you can understand. Although you have marked Remy's answer as accepted you clearly don't understand it. If you don't understand it now, just imagine the fun you will have when you come back to this in the future. I guess you just enjoy pain! ;-) – David Heffernan Mar 29 '12 at 19:38
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/9478/discussion-between-david-heffernan-and-tprice88) – David Heffernan Mar 29 '12 at 19:38
  • 1
    Very funny discussion :) I think Tprice88 wrote c not C because for c is the ASCII code 99. – riv333 Mar 29 '12 at 19:49

3 Answers3

6

You have to store the contents of the word that you are writing somewhere. WriteProcessMemory expects a pointer to some memory in your process space. If you don't want to use a variable, use a constant.

const
  DriftMul: word=99;
....
WriteProcessMemory(HandleWindow, ptr($4E709C),  @DriftMul, 2, Write);

Passing ptr(99) fails because ptr(99) is not a pointer to a word containing the value 99. It is a pointer to address 99. I think you were trying to write @Word(99) but you cannot take the address of a true constant.

You can make this more convenient by wrapping up the call to WriteProcessMemory in a helper methods. Although your question suggests that you want to write Word values, it became apparent in out lengthy chat that you actually want to write byte sequences. Writing integer data types will lead to machine endianness confusion. So instead I would do it using an open array of Byte to give the flexibility at the call site.

procedure WriteBytes(hProcess: THandle; Address: Pointer;
  const Buffer: array of Byte);
var
  NumberOfBytesWritten: DWORD;
begin
  if not WriteProcessMemory(hProcess, Address, @Buffer[0], Length(Buffer),
    NumberOfBytesWritten) then RaiseLastOSError;
end;

You can then call the code

WriteBytes(Handle, Pointer($523328), [$42]);//single byte
WriteBytes(Handle, Pointer($523328), [$CC, $90, $03]);//3 bytes
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • So in Delphi theirs no way to write without storing the value somewhere? – Tprice88 Mar 29 '12 at 17:26
  • There is no way to create a pointer to a word containing a value, without having a place to store it, just like he said. – Warren P Mar 29 '12 at 17:35
  • what about a byte or a int. For the address you dident have to store it anywhere so their should be a way for the bytes also. – Tprice88 Mar 29 '12 at 17:36
  • What about a byte or int? What's your question? – David Heffernan Mar 29 '12 at 17:38
  • For my 3rd parameter i want to put a byte their without storing the value anywhere. If theirs no way to do this i might have to make a function that creates one and i can just call it. – Tprice88 Mar 29 '12 at 17:42
  • Also, Delphi is not unusual. You'd need to declare storage in any language. – David Heffernan Mar 29 '12 at 17:42
  • above is a c++ Example and im able to do it without storing it anywhere. – Tprice88 Mar 29 '12 at 17:43
  • Why would a byte be different? Think about it. The API function needs a pointer to addressable memory. – David Heffernan Mar 29 '12 at 17:43
  • You can write a byte with: const value: byte = 99; WriteProcessMemory(HandleWindow, ptr($4E709C), @value, 1, Write); – riv333 Mar 29 '12 at 17:48
  • 1
    @Tprice88, your C++ example and your Delphi example are not equivalent. Your C++ example is writing a *string literal*, whereas your Delphi code writes an *integer*. C++ can get a pointer from a string literal because stings literals are arrays, and an array automatically converts to a pointer to its first element. So you have a pointer. Try passing an integer in C++, and it will fail the same way it fails in Delphi. – Rob Kennedy Mar 29 '12 at 21:34
  • @tprice88 are you for real? You are accepting the answer that doesn't even work and after I spent an hour helping you yesterday. – David Heffernan Mar 30 '12 at 06:27
  • your right i checked it and it dident work i took it off. thanks – Tprice88 Mar 30 '12 at 17:13
2

The ptr() Method converts an address to an pointer. So the value in the second method is not 99 but the value that is written at the address 99.

My dirty method, but with few lines of code:

procedure WriteBytes(hProcess: THandle; address: Pointer; buffer: Variant; count: Integer);
begin
  WriteProcessMemory(hProcess, address, @buffer, count, nil);
end;

Then you can call the method with:

WriteBytes(HandleWindow, Pointer($449A17), 90, 1);
riv333
  • 389
  • 2
  • 12
  • how can this work? First byte of a variant is not it's payload. – David Heffernan Mar 30 '12 at 06:29
  • In this case the variant is handled as integer. When the LSB is in the first byte it should work when not one must convert the value so that it fits. Its a dirty method i also not want to use, but if the goal is to get least lines of code as possible one can work with it. – riv333 Mar 30 '12 at 07:01
  • First byte of a variant is not the payload. It's the type information. – David Heffernan Mar 30 '12 at 07:05
  • Ah you sure? Hmm then one must modify the @buffer in the WriteBytes method so that the pointer shows on the payload. I am sorry i haven't Delphi installed yet to test it. It is only a template which shows the idea. Perhaps it needs some little modifications. – riv333 Mar 30 '12 at 07:11
  • A Variant is a really poor idea here. It's just come to me that OP actually wants flexible sequences of bytes as seen in his cheat engine hex editor. And that's an open array of Byte. – David Heffernan Mar 30 '12 at 07:27
  • I agree with you a array of bytes would be better. It was to late yesterday evening ;) Your method looks good, i will rate your answer. – riv333 Mar 30 '12 at 07:37
  • If your answer is going to be the accepted one then it really ought to be correct. Feel free to edit it and borrow whatever you like from my answer if you wish. I'd just rather than an accepted answer was accurate. – David Heffernan Mar 30 '12 at 08:06
2

In C++, this code:

WriteProcessMemory(hProcess, (void*)0x4E709C, (void*)(PBYTE)"\x20", 1, NULL); 

Is declaring a const char[] buffer in the app's memory that contains the two characters '\x20' and '\x00' in it. This is evident by the use of the " double-quote characters around the literal. They are creating a string literal, not a character literal (which uses ' single-quote character instead). The starting address of that literal's first character is being passed to the third parameter and the fourth parameter is set to 1 to tell WriteProcessMemory() to copy only 1 byte from that 2-byte buffer.

Delphi, on the other hand, uses the ' single-quote character around both single-character and string literals, and thus relies on code context to decide which type of literal needs to be created. As such, Delphi does not have a direct means of declaring a single-character literal that is the equivilent of an inlined char[] like in the C++ code. The closest equivilent I can think of right now, without declaring a constant, would be something like this:

WriteProcessMemory(hProcess, Pointer($4E709C), PAnsiChar(AnsiString(' ')), 1, nil); 

Otherwise, use just an explicit constant instead. The direct equivilent of what the C++ code is doing is the following:

const
  buffer: array[0..1] of AnsiChar = (#$20, #0);

WriteProcessMemory(hProcess, Pointer($4E709C), Pointer(PByte(@buffer[0])), 1, nil); 

Alternatively, you can simplify it to the following:

const
  space: Byte = $20;

WriteProcessMemory(hProcess, Pointer($4E709C), @space, 1, nil); 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Nice the method you made is actually working, i had one problem though. `WriteProcessMemory(HandleWindow, Pointer($449A17), PAnsiChar(AnsiString('C3')), 1, Write);` why would this make 43 – Tprice88 Mar 29 '12 at 18:49
  • @Tprice88 before you get too excited, just ask yourself how you are going to encode, for example, bytes with value <32. – David Heffernan Mar 29 '12 at 19:05
  • @Remy Why `Pointer(PByte(@buffer[0]))`? Why not `@buffer[0]`? – David Heffernan Mar 29 '12 at 19:20
  • @DavidHeffernan: I was showing what the C++ code is directly doing in Delphi terms, and it uses extra (redundant) casts. You will see that I took out the extra casts in the other Delphi example I showed. – Remy Lebeau Mar 29 '12 at 21:26