Shoutbox

Call ASM routine from your script (with example) - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: Call ASM routine from your script (with example) (/showthread.php?tid=97508)

Call ASM routine from your script (with example) by CookieRevised on 05-02-2011 at 07:21 AM

There are times that you have a binary string inside a (Plus!) DataBloc.
Now, there is a problem if you want to output that binary data for example in the debug window of your script, or if you want to manipulate it further in your script as being a normal string.

This because the ReadString() method will only read up until the first Null character ("\0"); and a binary string can of course contain much more data after a Null character.

You also can't use the ReadBSTR() method directly, because that binary string isn't a BSTR string (a BSTR is a unicode string prefixed with its length, thus, allowing for Null characters). Even if you would add the known length of that binary string in front of it, you still would need to convert it to 'pseudo' unicode first to be able to read it using ReadBSTR().

'pseudo' because all you need to do is add a Null byte (0x0) after each byte in the binary string. It isn't really unicode unicode in that way, but it can be read using unicode read functions like ReadBSTR().

You could use some Unicode conversation APIs for that (eg: MultiByteToWideChar API). But the problem with that is that those APIs will actually change some of the bytes into another byte + not a Null character; they actaully map the characters according to a 'code page', they do not simply append a Null byte after each byte. Aka they have the very real potential to mangle up the real data from the binary string and thus producing the wrong output.

In the end, what you probably end up with is something like this:

js code:
// BinaryData is a DataBloc containing bytes
// OutputString is going to be a BSTR, so we can output it using ReadBSTR()

var OutputString = Interop.Allocate(BinaryData.Size * 2 + 4 + 2);
// *2 because it contains a unicode string
// +4 to accomodate for the DWORD length
// +2 for the unicode termination Null character

// Add the size of the string into the first DWORD of the BSTR
OutputString.WriteDWORD(0, BinaryData.Size * 2);

>>>// Convert the binary DataBloc into a pseudo unicode string (aka append a Null character after each byte)<<<
>>>for (var i=0; i < BinaryData.Size; i++) {<<<
>>>    OutputString.SetAt(i * 2 + 4, BinaryData.GetAt(i));<<<
>>>}<<<

// Read out the BSTR string and output it
Debug.Trace(OutputString.ReadBSTR(0));

Now, this will work, but it will be dead slow. So, in many cases it is realy useless. For example, think about outputting a memory dump of 10000 bytes with the above code. But what if we can replace that slow loop function with assembler code (you can't go any faster than that)? Wouldn't that be cool? Well, you can:

js code:
// BinaryData is a DataBloc containing bytes
// OutputString is going to be a BSTR, so we can output it using ReadBSTR()

var OutputString = Interop.Allocate(BinaryData.Size * 2 + 4 + 2);
// *2 because it contains a unicode string
// +4 to accomodate for the DWORD length
// +2 for the unicode termination Null character

// Add the size of the string into the first DWORD of the BSTR
OutputString.WriteDWORD(0, BinaryData.Size * 2);

>>>// Create our ASM routine<<<
>>>// It takes the memory pointer to a byte array as input and copies the individual bytes to the memory offset given in the second paramater,<<<
>>>// but each time increasing the memory offset by two (instead of by one). Thus essentially doubling its size. eg: \1\2\3 is copied as \1\0\2\0\3\0.<<<
>>>var sASM = "\u8B55\u244C\u8B10\u2454\u8B0C\u246C\u6608\uB60F\u0045\u8966\u4502\u4242\uF3E2\uC25D\u0010";<<<
>>>var oASM = Interop.Allocate(sASM.length * 2 + 2);<<<
>>>oASM.WriteString(0, sASM);<<<

>>>// Call the mighty ASM routine<<<
>>>// Here the 'magic' happens; we (ab)use the CallWindowProc API.<<<
>>>Interop.Call("User32", "CallWindowProcW", oASM.DataPtr, BinaryData.DataPtr, OutputString.DataPtr + 4, BinaryData.Size, null);<<<

// Read out the BSTR string and output it
Debug.Trace(OutputString.ReadBSTR(0));
This code will run as good as instantly because of the used ASM:
js code:
/*
      HEX             ASM
0000  55              push    ebp            ; save old frame pointer
0001  8B 4C 24 10     mov     ecx, [esp+10h] ; copy value of parameter 3 (=length of input string) into counter register (CX)
0005  8B 54 24 OC     mov     edx, [esp+0Ch] ; copy value of parameter 2 (=mem adress of output string) into data register (DX)
0009  8B 6C 24 08     mov     ebp, [esp+8]   ; copy value of parameter 1 (=mem adress of input string) into base pointer register (BP)
                      'start':
000D  66 0F B6 45 00  movzx   ax, byte ptr [ebp+0] ; copy byte value from mem adress stored in EBP to AX
0012  66 89 02        mov     [edx], ax      ; copy AX to mem adress stored in EDX
0015  45              inc     ebp            ; increment EBP
0016  42              inc     edx            ; increment EDX
0017  42              inc     edx            ; increment EDX
0018  E2 F3           loop    'start'        ; decrement ECX and jump to 'start' if CX!=0
001A  5D              pop     ebp            ; restore old frame pointer
001B  C2 10           retn    10h            ; end
*/

---------

EDIT:

Apparently there was already another nice example of using ASM in scripting, created by Mnjul some time ago here (note: thread is in beta testing section, so only beta testers can access it) and Matty used it to create this script.

The principle is just the same: write the ASM code and use the opcodes (=the hexadecimal values) to make a binary data string and place that in memory.

His script uses the WriteProcessMemory API to inject (asm) code into the process memory (but not yet run it!), rerouting the default call to the WinProc procedure to this code instead, and calling the 'old' WinProc procedure after the new injected code has finished.
RE: Call ASM routine from your script (with example) by SmokingCookie on 05-02-2011 at 01:46 PM

Wow, nice explanation :O

Unfortunately, it doesn't work :P If I create BinaryData as follows:

JScript code:
var Text = "Hello world!";
var BinaryData = Interop.Allocate((Text.length + 1) * 2);
BinaryData.writeSTRING(0,Text);

Then the debugger output is an empty string for the first method, and an H for the second.
RE: RE: Call ASM routine from your script (with example) by CookieRevised on 05-02-2011 at 05:17 PM

[actually off topic as it will be more about explaining what unicode is and how strings are stored than about using ASM in scripting]

quote:
Originally posted by SmokingCookie
Unfortunately, it doesn't work :P If I create BinaryData as follows:

JScript code:
var Text = "Hello world!";
var BinaryData = Interop.Allocate((Text.length + 1) * 2);
BinaryData.writeSTRING(0,Text);

Then the debugger output is an empty string for the first method, and an H for the second.
It does work...
If the debug output showed an empty string for the first method then you've made an error in your code.

In both cases it should show just an 'H' !
It is the correct output for your 'hello world' example.

This because you already starting from a unicode string (note: it is not meant to be used like that). In JScript strings are always already unicode. Hence the very exact reason for this conversion example. So essentially, what you did was converting an unicode string to an unicode string. In other words the second character will always be a null character in that case. And a null character can not be shown in the debug output (but that doesn't mean it isn't there or that there isn't more stuff after that).

In other words, what you did was converting this binary data:
48 00 65 00 6C 00 6C 00 6F 00 20 00 57 00 6F 00 72 00 6C 00 64 00 21 00 (This is the actual content of your variable Text, a unicode string "Hello World!")
into this:
48 00 00 00 65 00 00 00 6C 00 00 00 6C 00 00 00 6F 00 00 00 20 00 00 00 57 00 00 00 6F 00 00 00 72 00 00 00 6C 00 00 00 64 00 00 00 21 00 00 00

The bold part shows the first character in the string before conversion and where those same bytes are after the conversion.
The underlined part is what makes the second (unicode) character in the string before and after the conversion.
The blue bytes are the original bytes shown where they are before and after the conversation.
The black 0x00 bytes are what is added (actually skipped) by the function to make the original binary data (eg: binary data you read from the registry) into a real (unicode) string which you can use in JScript to manipulate (eg: to search for certain characters, to extract a certain substring, etc, using the conventional JScript functions and methods).

As you can see, the second (unicode) character after the conversion is a null character, which you can not display, and the output will stop after encountering a null character.

So, instead of displaying the entire string as a whole, I suggest you use JScript's string.charAt() method to examine what is going on in the strings before and after the conversion. (charAt() shows the character code of the unicode character).

And/or use this string to start with (it is the "Hello World!" in ansi):
js code:
var Text = "\u6548\u6C6C\u206F\u6F57\u6C72\u2164";
// note that this string is still a unicode string. However here we also use the higher bytes (which would otherwise be 0x00 for the common ascii characters. Thus actually mimicing an ansi string or byte array.
Or change your test code to:
JScript code:
var Text = "Hello world!";
var BinaryData = Interop.Allocate(Text.length + 1);
BinaryData.writeSTRING(0, Text, false);
// note the added parameter 'false' which writes the string as an ansi string into the memory block


[/actually off topic]

RE: Call ASM routine from your script (with example) by SmokingCookie on 05-02-2011 at 06:45 PM

Okay, you win (again...) :p

But what does the ASM thing do? In other words: what is this?

JScript code:
var sASM = "\u8B55\u244C\u8B10\u2454\u8B0C\u246C\u6608\uB60F\u0045\u8966\u4502\u4242\uF3E2\uC25D\u0010";

And how did you make that up? :|
RE: Call ASM routine from your script (with example) by CookieRevised on 05-02-2011 at 07:07 PM

See the comment at the end of the script in the first post.

You write ASM using mnemonics (third column), this is the language syntax and code style you use to write ASM (just like var x= '' is JScript code). Each mnemonic (or 'command' if you will) has an equivalent series of bytes (sometimes just 1 byte) called opcodes, these are shown in the second column.

eg: 'push ebp' translates to the opcode 0x55.

Note: patchers quite often do a simple replace of opcodes. This often means they change one command into another command in the ASM code.


RE: RE: Call ASM routine from your script (with example) by segosa on 05-02-2011 at 07:07 PM

quote:
Originally posted by SmokingCookie
Okay, you win (again...) :p

But what does the ASM thing do? In other words: what is this?
JScript code:
var sASM = "\u8B55\u244C\u8B10\u2454\u8B0C\u246C\u6608\uB60F\u0045\u8966\u4502\u4242\uF3E2\uC25D\u0010";

And how did you make that up? :|

Look at each hex value next to the assembly, and compare. It's the machine code/shellcode/opcodes/whatever you want to call it.

CookieRevised: I have no useful input to add to this thread, so all I can say is that I really like this. If code could turn me on, this would.
RE: Call ASM routine from your script (with example) by matty on 05-02-2011 at 07:07 PM

This is the actual thread...
Help me test script (Ctrl-W Closer) :D


RE: Call ASM routine from your script (with example) by SmokingCookie on 05-02-2011 at 07:18 PM

I see what y'all mean, but I was actually wondering what the effect of the ASM stuff is on the "Hello world!" string. I mean: the input is the same as the output? And I think this ASM is quite a bit too abstract to make up yourself, right?

@matty: I don't have access to the thread you're pointing to.

(LoL at 3 people posting at the same time :P )


RE: Call ASM routine from your script (with example) by CookieRevised on 05-02-2011 at 08:04 PM

quote:
Originally posted by matty
This is the actual thread...
Help me test script (Ctrl-W Closer) :D
Ah, thanks... added.
quote:
Originally posted by segosa
CookieRevised: I have no useful input to add to this thread, so all I can say is that I really like this. If code could turn me on, this would.
thanks... I think :p as long as you don't cum....
quote:
Originally posted by SmokingCookie
I see what y'all mean, but I was actually wondering what the effect of the ASM stuff is on the "Hello world!" string. I mean: the input is the same as the output?
Nope, the output is completely different than the input. See my previous post where I explain what the effect is using your "hello world" example.

quote:
Originally posted by SmokingCookie
And I think this ASM is quite a bit too abstract to make up yourself, right?
Although I got help from wtbw, there is nothing magic about it. It is just a matter of knowing your commands. (eg: how to write x++, or x=5 in asm). If you wouldn't know JScript, then any JScript code would be "abstract" to you too, won't it? So, that goes for any programming language code, including asm.

The only difference is that asm is as low as you can go, it is (almost) pure machine code. So it doesn't have fancy (and human readable) commands which actually automatically do 1000 other things under the hood for you. You need to write those 1000 commands yourself in that case, using a set of simple and basic (cryptic, but still understandable in a way) commands.

eg:
mov ax, [cx]    means move (or rather copy) the value found in the address pointed to by the register CX, to the register AX.
inc ax             means increment the value in AX and store that new value again in AX

If you wanna know more about those mnemonics I suggest to Google assembler language and such things. Plenty info around, but not for the faint-hearted (or old people like me who cba anymore to learn it properly :p).

quote:
Originally posted by SmokingCookie
@matty: I don't have access to the thread you're pointing to.
That thread is in beta testing forum.
See OP for a link to matty's implementation of that code in the public forum.
RE: Call ASM routine from your script (with example) by Mnjul on 05-03-2011 at 01:00 AM

quote:
Originally posted by SmokingCookie
@matty: I don't have access to the thread you're pointing to.
If you're interested, the script is available here: http://www.msgplus.net/Downloads/Download-Details/DocumentID/8127/ but without the nice discussions in the beta forum :p
RE: Call ASM routine from your script (with example) by whiz on 05-04-2011 at 07:25 AM

This is actually quite interesting for me, since I'm doing a Computing A-level and there's a bit about assembly and machine code in it...  good to actually see it in use. :)