Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

AHK_L Decompiler (Payload Method)


  • Please log in to reply
69 replies to this topic
nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
Very impressive. I've been warning people against this for a long time. Even with mpress, there's no such thing as source protection for AHK. Go learn C++ :p

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
PatternScanPureAHK() has a bug:
scan := 1
...should be...
currentNeedle := magic[scan := 1]
...to reset the byte value which it is looking for.

I am unable to get the mcode version to work with any compressed or uncompressed script - it always returns exception 0xc0000005 (access violation).

I am also unable to extract any mpress-compressed script using the generic unpacker (after switching from mcode to script). It does not find "COMPILER:" or "MsgBox" (which is all the script contained). Edit: Neither string exists in the memory dump. Edit: This appears to be because the dump is running before the script data is decompressed into memory. Waiting for ahk_class AutoHotkey ahk_pid %pid% allows it to work.

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
MPRESS v2.19's 32-bit executable packer is bugged, probably because side-effects of a fix the author made for v2.18's bugged 64-bit executable packer. In the mean time, use v2.18 for packing 32-bit executables and v2.19 for 64-bit ones.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
fincs: Apparently I'm using v2.16b.

IsNull: This method of scanning is much faster than PatternScanPureAHK(), enough that there isn't any point in using an external dll or mcode.
FindMagic(byref buffer, size, magic, offset=0){
   magicLen := ByteArrayToBuffer(magic, magicBuffer)
   magicByte := magic[1]
   searchPtr := &buffer + offset
   searchEnd := &buffer + size - magicLen + 1  ; First byte must precede searchEnd.
   if(searchPtr >= searchEnd)
      return -1
   while searchPtr := DllCall("msvcrt\memchr", "ptr", searchPtr, "int", magicByte
                              , "ptr", searchEnd - searchPtr, "ptr"){
      if !DllCall("msvcrt\memcmp", "ptr", searchPtr, "ptr", &magicBuffer, "ptr", magicLen)
         return searchPtr - &buffer + magicLen - 1  ; I think this is what the script expects...
      ++searchPtr  ; Resume search at the next byte.
   }
   return -1
}
You may want to just pass the magic data directly instead of converting it to/from an array.

Btw, your method of decompilation fails with AutoHotkey 1.0. Aside from one or two lines of text in temporary buffers, the script text is removed from memory when the script finishes loading. As a consequence, your method only works if the script encounters a load-time error, or if the dump somehow occurs between start and end of the script loading process.



CAUTION: One line of code at the end of Script::LoadIncludedFile is all it takes to cause this decompiler to display a false script.
strcpy((LPSTR)textbuf.mBuffer, "; <COMPILER: v" AHK_VERSION ">\nMsgBox, Hello, World!");
My initial idea was to zero the memory, but this better demonstrates the inherent flaw in this method of decompilation. Another way to confuse it would be to move the "magic" bytes to another part of the file, but that wouldn't stop someone finding the actual script in the complete memory dump.

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
Lexikos, thanks for the improved AHK Pattern search, this really performs equally well. I've changed the script and removed the old Mcode version.

I am unable to get the mcode version to work with any compressed or uncompressed script - it always returns exception 0xc0000005 (access violation).

I've tuned the asm code to only use relative jumps thus I expected it to work on any 32bit Intel-Compatible CPU.

Another way to confuse it would be to move the "magic" bytes to another part of the file, but that wouldn't stop someone finding the actual script in the complete memory dump.

Actually, you can scan for any string (common AHK keywords etc) which probably exists whithin the script, as by default, it scans also for the upperbound of the string. If you are curious, one can even tune the offset to skip the first found skript :)

Zero it from the Memory would be a protection against it, as it would cause a race condition which would cause the decompilation to fail very likely.

Well, there is another method to retrive the script based on the fact, that the resource is present and accessible after the EXE is unpacked in Memory.
The process must be hooked after the exe has been loaded, but before it can execute anything.

A Mpress specific solution could be, patching the adress where Mpress wants to get control back to the original exe. Thus, the thing lies in memory and is paralyzed, and the resources can be accessed.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Actually, you can scan for any string (common AHK keywords etc)
which probably exists whithin the script, as by default, it scans also for the upperbound of the string. If you are curious, one can even tune the offset to skip the first found skript

All useful only if the user of the decompiler knows what they initially get isn't the real script.

Zero it from the Memory would be a protection against it, as it would cause a race condition which would cause the decompilation to fail very likely.

During my testing with your unmodified script on compressed scripts, the failure rate was 100% merely because it didn't wait long enough. It's unlikely to get the timing just right without some sort of signal to look for.

Well, there is another method to retrive the script based on the fact, that the resource is present and accessible after the EXE is unpacked in Memory.

I figured, but I'd like to see how feasible it is.

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007

I figured, but I'd like to see how feasible it is.




New approach 8-) It works now without any memory analysis and also does not allow the script being executed. Have fun!

ZeLen1y
  • Members
  • 44 posts
  • Last active: Oct 13 2014 09:43 PM
  • Joined: 11 Oct 2006
Great! Thanks!

  • Guests
  • Last active:
  • Joined: --
Doesn't work
I tried it on compressed and uncompressed test compiled script
used upx, mpress and petite

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
I've fixed a little issue, where as the extracted script was not written down to the disk fast enough to be read in again. Therefore, I added a little waiter to fix it. Please try again.

If it not works, post your OS specifications.

  • Guests
  • Last active:
  • Joined: --
It works now.
By the way, on my system msvcr100.dll was missing, maybe you should download it in that case? Alittle easier users who don't have it.

Thanks anyway, much appreciated :)

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

By the way, on my system msvcr100.dll was missing,

It's the Microsoft Visual C++ 2010 runtime.

IsNull: If you specify static linking for the C runtime when the payload dll is compiled, it won't depend on this file. If you don't use C runtime functions, you can exclude it entirely.

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
Well, I just tested this decompiler, and it tells me this:

<Recover Source for F:\(REMOVED)\Auto Hotkey\TestEncrypt.exe>
<Starting file analysis...>
<Whatever you dragged here, this is NOT a valid PE file.>
<File seems not to be a valid compiled AHK Script or it uses an unknown protection.>
Its not even encrypted or compressed.
It seems to not work on any of my AHK exe's.

Windows 7 32bit, 32bit ANSI programs.

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
@Lexikos: I 'll start optimizing dependencies and file sizes when it can be considered a stable build. Thanks for pointing out how to reduce the binary size. For the next release, I think using static compiling might reduce some issues users have right now for the price of a bigger download.

@gamax92: Quite impressive. "<Whatever you dragged here, this is NOT a valid PE file.>" means that the first two bytes in the file ARE NOT "MZ" which is actually present in any PE file. (Its the old DOS Header, which begins with the initials of Mr. Mark Zbikowski)
Either its a silly bug, probably an issue reading the file, or the exe is very strange and should not even be executable.

Hum, I probably should start using proper Versioning and provide a changelog for this project and give long term support. Actually, it was planed as a one time release and proof of concept. But u know, this Community is cool. :mrgreen:

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
Well, Just hex edited the exe. Does contain MZ as the first 2 chars, and later the PE signature is present.

ERM, HasPEHeaderMagic() is reading the strings, M and R

EDIT2: The issue is because I'm running the decompiler as ANSI, and when I compile it as Unicode, it then detects the Z properly.
When I ran it on Unicode, I was able to get the Source Code.

EDIT3: Well, I just ran it on a special program and some of the code was a bit mangled.

TextToType := "·š““"
Loop, % StrLen(TextToType)
   Encode .= Chr(255 - Asc(SubStr(TextToType,A_Index,1)))
MsgBox, %Encode%
became
TextToType := "·š““"
Loop, % StrLen(TextToType)
Encode .= Chr(255 - Asc(SubStr(TextToType,A_Index,1)))
MsgBox, %Encode%

EDIT4: Teh hell, now I cant run any of my ahk programs. They all decompile instead. WTF even Ahk2Exe.exe from _L doesnt work.

EDIT5: And I rebooted and now they are working again.

EDIT6: Oh and I just figured out how to rename those Magic Patterns your decompiler uses.