Jump to content

Execute in a different thread


trancexx
 Share

Recommended Posts

Win 7 - 64-bit

If you're running the x64 version of autoit then it's no wonder. trancexx have written x86 compatible code not x64-x86.

And, yes, I see you do that right now.

Edited by monoceres

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

If you're running the x64 version of autoit then it's no wonder. trancexx have written x86 compatible code not x64-x86.

And, yes, I see you do that right now.

Makes sense....and it works now :)

Great job!

[left][sub]We're trapped in the belly of this horrible machine.[/sub][sup]And the machine is bleeding to death...[/sup][sup][/sup][/left]

Link to comment
Share on other sites

  • 2 months later...
  • 2 months later...

Hi, trancexx.

This is a great script. Can you explain how it is working? I was trying to implement this function to be run in another thread but never succeeded, can you help me with this? I'm trying to make it run in another thread continuously - cpu usage.

$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\CIMV2")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Processor", "WQL", 0x10 + 0x20)
If IsObj($colItems) Then
 For $objItem In $colItems
 GuiCtrlSetData ($statuslabel, $objItem.LoadPercentage & " %")
 Next
EndIf

That script, and many others on the same subject, is building processor's set of instructions on the fly. You might say it produces the same code as any compiler/linker that are later fed processor with. Processor processes those instructions and you get desired results.

If you want to use this technique for writing code that you normally wouldn't be able in AutoIt (threads, speed...) you have to have some pre-knowledge or big balls :mellow: . Since you don't just don't.

Or better yet, read, read, read... I myself wrote like dozens of posts here on AutoIt forum on the subject, not to mention some others. And this forum is like a small place.

Ajde, ajde, sta se treses? Nije ti ovo toliko tesko. Jednom kad shvatis o cemu se radi vidjet ces da je to macji kasalj.

Edited by trancexx

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

  • 4 weeks later...

I'm introducing myself to x64 environment for the past few days.

The result of that is, among other things, 64bit support for this script (function). First post - attached file.

What's new to me on x64? Primarily calling convention and stack handling.

After short introduction I can say "wow! cool". Fastcall used for x64 code is very similar to coding in AutoIt. There is almost never stack to handle, all goes to registers that are then passed to functions. There is no more push, push, push... call(...). Now it's:

$rcx = param1
$rdx = param2
$r8 = param3
$r9 = param4
CALL $pFunction
And parameters for that function will be ($rcx, $rdx, $r8, $r9).

If some function take up to four parameters registers are filled and passed in this order, as shown: rcx, rdx, r8, r9. After that if there are more parameters you use stack.

Reserving space on the stack is in this manner; if it wouldn't be used (4 or less params) then 8 bytes is reserved:

sub rsp, 8d
Otherwise because of alignment (16) you reserve 24 or 40 or 56 or... whatever_you_need bytes.

When you are done undo like this (same amount):

add rsp, 8d
After call the return value is in rax.

Seems easy enough. :(

Edited by trancexx

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

  • 4 months later...

trancexx,

While I didn't take a look at this before, I've taken a look now (you directed me here from your GIF Animation thread), and decided to see what you did with x64 code since you are one of a small few that use Assembly language in their code, and of course I'd like to think you would choose to do it correctly. Unfortunately, there is a small matter to be fixed:

The register back-store is not created by your code, which is a required part of the x64 calling convention. Luckily all you need to do to the code is change 'sub rsp, 8d' to 'sub rsp, 40d', and 'add rsp, 8d' to 'add rsp, 40d'. Not doing so can risk the called functions overwriting the Thread return address as well as any other data within the register back-store range (32 bytes beyond the return address of a called x64 function).

Link to comment
Share on other sites

trancexx,

While I didn't take a look at this before, I've taken a look now (you directed me here from your GIF Animation thread), and decided to see what you did with x64 code since you are one of a small few that use Assembly language in their code, and of course I'd like to think you would choose to do it correctly. Unfortunately, there is a small matter to be fixed:

The register back-store is not created by your code, which is a required part of the x64 calling convention. Luckily all you need to do to the code is change 'sub rsp, 8d' to 'sub rsp, 40d', and 'add rsp, 8d' to 'add rsp, 40d'. Not doing so can risk the called functions overwriting the Thread return address as well as any other data within the register back-store range (32 bytes beyond the return address of a called x64 function).

I would think 8 byes is enough because (I would assume) function(s) I call are written/compiled to avoid situation you mention.

Let me take a look inside InternetCheckConnectionW to see if that's the case.

x64 code:

$hModule = _LoadLibraryEx("wininet.dll")

$pAddress = _GetAddress($hModule, "InternetCheckConnectionW")
ConsoleWrite("InternetCheckConnectionW address = " & $pAddress & @CRLF)

$tByteStructure = DllStructCreate("byte[256]", $pAddress) ; don't mind the size. It's irrelevant for this
ConsoleWrite(DllStructGetData($tByteStructure, 1) & @CRLF)

Func _LoadLibraryEx($sModule, $iFlag = 0)
    Local $aCall = DllCall("kernel32.dll", "handle", "LoadLibraryExW", "wstr", $sModule, "handle", 0, "dword", $iFlag)
    If @error Then Return SetError(1, @error, 0)
    Return $aCall[0]
EndFunc   ;==>_LoadLibraryEx

Func _GetAddress($hModule, $vFuncName)
    Local $sType = "str"
    If IsNumber($vFuncName) Then $sType = "int" ; if ordinal value passed
    Local $aCall = DllCall("kernel32.dll", "ptr", "GetProcAddress", "handle", $hModule, $sType, $vFuncName)
    If @error Or Not $aCall[0] Then
        Return SetError(1, 0, 0)
    EndIf
    Return $aCall[0]
EndFunc   ;==>_GetAddress

For me that returned:

0x488BC44889581048896818565741544883EC2033DB33FF33F6215808418BE8448BE2488958204885C9741B4C8D48084C8D402083CAFFE885C5F9FF488B5C24588BF885C07510448BC5418BD4488BCBE8A0E9FFFF8BF04885DB7409488BCBFF15A840050085FF74088BCFFF15A4400500488B5C2448488B6C24508BC64883C420415C5F5EC39090909090909048895C2408574881EC80000000488BDA33D2488BF9448D4258488D4C2420E84D49F9FF488D4C2420E81395F9FF41B801000000488BD3488BCFE87668FBFF488D4C2420488BD8E86595F9FF488BC3488B9C24900000004881C4800000005FC3909090909090909090488BC4488968084889701057

Let's see if I can make some sense there. I can spot patterns. Can write this:

488BC4
48895810
48896818
56
57
4154
4883EC20
33DB
33FF
33F6
;...

Out of that:

488BC4          mov rax, rsp
48895810        mov [rax+16d], rbx
48896818        mov [rax+24d], rbp
56              push rsi
57              push rdi
4154            push r12
4883EC20        sub rsp, 32d
33DB            xor ebx, ebx
33FF            xor edi, edi
33F6            xor esi, esi
;...

So, it's:

mov rax, rsp
mov [rax+16d], rbx
mov [rax+24d], rbp
push rsi
push rdi
push r12
sub rsp, 32d
xor ebx, ebx
xor edi, edi
xor esi, esi
;...
Can you interpret that code for me and implications of it to the code that follows? I'm serious and want to learn so please don't ignore this. Edited by trancexx

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

Reverse-engineering and looking inside API functions isn't exactly good practice for basing your own code on, not to mention that at any given time Microsoft may change certain DLL's in O/S updates (so long as the functionality stays the same). But overlooking that idea, let's look at the code you pulled from the function as you have disassembled it:

So here's what happens (remember, x64 registers are 8 bytes (64-bits), return addresses included):

mov rax, rsp    ; RAX is set to the RSP stack pointer. RSP currently points to an 8-byte return address, and now so does RAX
mov [rax+16d], rbx ; RBX, a non-volatile register, is saved into the register back-store area (+8 = beyond return, +8 = the typical RDX back-store area)
mov [rax+24d], rbp ; RBP, another non-volatile register, is saved into the register back-store area (+8 beyond RDX = the typical R8 back-store area)
push rsi    ; It could save 2 more into that area here, but just pushes these non-volatile registers
push rdi    ; ..decreasing the stack by 8 each time (and altering RSP - RAX however remains as it was on entry)
push r12    ; Since this is a 3rd push, the stack is now evenly aligned (on-entry, it was 8-byte aligned, now -24 = -32 (16-aligned))
sub rsp, 32d    ; This prepares either a local storage area, or a register-store area for future calls
xor ebx, ebx    ; Zeroes ebx
xor edi, edi    ; Zeroes edi
xor esi, esi    ; Zeroes esi

So lets see - by the 2nd instruction it is already overwriting your Thread's return address with rbx because you didn't provide the register back-store. All you added was 8 to RSP, which aligned the stack properly, but didn't create a proper register back-store area (32-bytes). It should be 40 because of the added alignment however, since on function/Thread entry it is always on an 8-byte alignment, yet needs to be 16-byte aligned prior to a call. So 32 (register back-store) + 8 (alignment) = 40.

As far as the 'implications' of the code go, I can't give you much more than I have above without knowing the rest of the function. However, within the function, RBX, RBP, RSI, RDI, and R12 can be freely modified by the rest of the code, right up to the point where they are popped from the stack (after a 'add rsp, 32d' instruction most likely). When I call them 'non-volatile', what is meant is that these registers are required to be in the same state as they were prior to the call.

Volatile registers (ones that can be freely altered without being preserved) consist of RAX, RCX, RDX, R8, R9, R10, R11 - and 128-bit floating point registers XMM0 through XMM5. The non-volatile registers consist of RBX, RBP, RDI, RSI, R12, R13, R14, R15 - and 128-bit registers XMM6 through XMM15.

Does any of that help at all?

P.S. You do realize there are disassemblers that can save you from all of this opcode->instruction conversion, yes?

*edit: worded RSP stack pushes as 'increasing' rather than decreasing (as RSP moves backwards)

Edited by Ascend4nt
Link to comment
Share on other sites

P.S. You do realize there are disassemblers that can save you from all of this opcode->instruction conversion, yes?

Why would I wanted to be saved from that?? I want the opposite. Isn't that obvious?

I'm not interested in using disassemblers.

Btw, out of curiosity, you think I did something illegal in that post?

Thank you for the interpretation. I need to think.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

edit: Proper stack handling for the x64 code. Thanks Ascend4nt.

trancexx, Sorry the subject has to be revisited - but you didn't update the code at all from what I see (you still only subtract 8 for the stack). The return address is still overwritten (as verified in a debugger).

However after looking more closely at your code it seems the thread never actually returns, so that would certainly explain why you don't get a crash. Otherwise, if that thread actually did return, you'd most certainly crash AutoIt x64.

Anyway, since the Thread just keeps going and going, it is fairly safe. Just keep the stack in mind going forward ;)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...