Jump to content

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

Machine code functions: Bit Wizardry


  • Please log in to reply
144 replies to this topic
olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005
XTEA in ECB mode without padding or chiphertext stealing (no AHK loops at all :) ):
#NoEnv
;#include FileHelper.ahk

MCode(ByRef code, hex) { ; allocate memory and write Machine Code there 
   VarSetCapacity(code,StrLen(hex)//2) 
   Loop % StrLen(hex)//2 
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char") 
} 

MCode(enc, "5589E557565383EC24C745F000000000C745ECB979379E8B4510C1E8038945D8C745E8000000008B45E83B45D80F831F0100" 
. "00C745F000000000C745E4000000008B45E43B45140F83FB0000008B45E88D34C5000000008B7D088B45E8C1E0038945D48B45088945D" 
. "08B45E8C1E00303450883C0048B0089C2C1E2048B45E8C1E00303450883C0048B00C1E80531C28B45E8C1E00303450883C00489D30318" 
. "8B45F083E0038D0C85000000008B550C8B45F003041131D88B55D48B4DD003040A89043E8B55EC8D45F001108B45E8C1E0030345088D7" 
. "0048B45E8C1E0030345088D78048B45E88D14C5000000008B45088B040289C1C1E1048B45E88D14C5000000008B45088B0402C1E80531" 
. "C18B45E88D14C5000000008B450889CB031C028B45F0C1E80B83E0038D0C85000000008B550C8B45F003041131D8030789068D45E4FF0" 
. "0E9F9FEFFFF8D45E8FF00E9D5FEFFFF83C4245B5E5F5DC3") 

MCode(dec, "5589E557565383EC24C745F000000000C745ECB979379E8B4510C1E8038945D8C745E8000000008B45E83B45D80F832A0100" 
. "008B45EC0FAF45148945F0C745E4000000008B45E43B45140F83030100008B45E8C1E0030345088D70048B45E8C1E0030345088D78048" 
. "B45E88D14C5000000008B45088B040289C1C1E1048B45E88D14C5000000008B45088B0402C1E80531C18B45E88D14C5000000008B4508" 
. "89CB031C028B45F0C1E80B83E0038D0C85000000008B550C8B45F003041189DA31C28B0729D089068B55EC8D45F029108B45E88D34C50" 
. "00000008B7D088B45E8C1E0038945D48B45088945D08B45E8C1E00303450883C0048B0089C2C1E2048B45E8C1E00303450883C0048B00" 
. "C1E80531C28B45E8C1E00303450883C00489D303188B45F083E0038D0C85000000008B550C8B45F003041189DA31C28B4DD48B5DD08B0" 
. "41929D089043E8D45E4FF00E9F1FEFFFF8D45E8FF00E9CAFEFFFF83C4245B5E5F5DC3") 

MCode(k, 11111111222222223333333344444444) ; 128 bit key 

u = 
( Join 
The simplest of the encryption modes is the electronic codebook (ECB) mode. The message is divided into block
s and each block is encrypted separately. The disadvantage of this method is that identical plaintext blocks a
re encrypted into identical ciphertext blocks; thus, it does not hide data patterns well. In some senses, it d
oesn't provide serious message confidentiality, and it is not recommended for use in cryptographic protocols at all.
The simplest of the encryption modes is the electronic codebook (ECB) mode. The message is divided into block
s and each block is encrypted separately. The disadvantage of this method is that identical plaintext blocks a
re encrypted into identical ciphertext blocks; thus, it does not hide data patterns well. In some senses, it d
oesn't provide serious message confidentiality, and it is not recommended for use in cryptographic protocols at all.
The simplest of the encryption modes is the electronic codebook (ECB) mode. The message is divided into block
s and each block is en...
) 

Loop, 1024
  v .= u 

len := StrLen(v) 

MsgBox, Encrypting 1 MB now... 
StartTime := A_TickCount 
DllCall(&enc, "uint",&v, "uint",&k, "uint",len , "uint",64) 
ElapsedTime := A_TickCount - StartTime 
MsgBox,  %ElapsedTime% milliseconds have elapsed. 
MsgBox % v 

;ReadMemory("output.enc", &v, len) 
;v = empty
;WriteMemory("output.enc", v)

MsgBox, Decrypting 1 MB now... 
StartTime := A_TickCount 
DllCall(&dec, "uint",&v, "uint",&k, "uint",len , "uint",64) 
ElapsedTime := A_TickCount - StartTime 
MsgBox,  %ElapsedTime% milliseconds have elapsed. 
MsgBox % v

Could the C code be optimised?
EEXPORT void XTEA_encipher_ECB(unsigned long* v, unsigned long* k, unsigned long len, unsigned long rounds) {
  unsigned long sum=0, delta=0x9E3779B9, i, j;

  unsigned long v0, v1;
  unsigned long blocks =  len/8;
 
  for(i=0; i<blocks; i++) {
    sum=0;
    
    for(j=0; j<rounds; j++) { 
      v[i*2] += (((v[i*2+1] << 4) ^ (v[i*2+1] >> 5)) + v[i*2+1]) ^ (sum + k[sum & 3]); 
      sum += delta; 
      v[i*2+1] += (((v[i*2] << 4) ^ (v[i*2] >> 5)) + v[i*2]) ^ (sum + k[(sum>>11) & 3]); 
    } 
  } 
}

EXPORT void XTEA_decipher_ECB(unsigned long* v, unsigned long* k, unsigned long len, unsigned long rounds) {
  unsigned long sum=0, delta=0x9E3779B9, i, j;

  unsigned long v0, v1;
  unsigned long blocks =  len/8;
  
    for(i=0; i<blocks; i++) {
    sum=delta*rounds;
  
      for(j=0; j<rounds; j++) { 
        v[i*2+1] -= (((v[i*2] << 4) ^ (v[i*2] >> 5)) + v[i*2]) ^ (sum + k[(sum>>11) & 3]); 
        sum -= delta; 
        v[i*2] -= (((v[i*2+1] << 4) ^ (v[i*2+1] >> 5)) + v[i*2+1]) ^ (sum + k[sum & 3]); 
        } 
  }
}

Edit 20070922: Added comments showing how to Disk I/O.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Nice! Have you thought about a C function ECB(function_address, extra_parameter, encryption_key, data_in_address, data_out_address, num_blocks), which accepts the address of any cipher or decipher function and performs ECB encryption or decryption (by calling the given function in a loop)? An extra paramater (like the number of rounds) could be also passed to the cipher.

One could define a cipher object {address of the algorithm, extra parameters, key}, and pass that to the ECB function...

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Here's a little function XOR'ing operand a with b and saving the result

It could be even more useful, if you XOR a number of bytes, and save the result in another location (which could be either a or B). It could function as a One Time Pad, an unconditionally secure encryption, but there are many-many other uses.

olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005

Nice! Have you thought about a C function ECB(function_address, extra_parameter, encryption_key, data_in_address, data_out_address, num_blocks), which accepts the address of any cipher or decipher function and performs ECB encryption or decryption (by calling the given function in a loop)? An extra paramater (like the number of rounds) could be also passed to the cipher.

One could define a cipher object {address of the algorithm, extra parameters, key}, and pass that to the ECB function...

That's a nice idea, it would be very elegant. But I guess my C knowledge is to little to implement this.

olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005

Here's a little function XOR'ing operand a with b and saving the result

It could be even more useful, if you XOR a number of bytes, and save the result in another location (which could be either a or B). It could function as a One Time Pad, an unconditionally secure encryption, but there are many-many other uses.

I see that it could be used more universally that way. Something like this?
/*
EXPORT void XOR_Stream_2(unsigned long* a, unsigned long* b, unsigned long len) {
  unsigned long i;
  for(i=0; i<len; i++) {
    a[i] ^= b[i];
  }
}
*/

MCode(ByRef code, hex) { ; allocate memory and write Machine Code there 
   VarSetCapacity(code,StrLen(hex)//2) 
   Loop % StrLen(hex)//2 
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char") 
} 

MCode(XOR_Stream, "5589E557565383EC04C745F0000000008B45F03B451073378B45F08D3485000000008B7D088B45F"
. "08D0C85000000008B5D088B45F08D1485000000008B450C8B040233041989043E8D45F0FF00EBC183C4045B5E5F5DC3")

a := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
VarSetCapacity(b, StrLen(a), Asc(A_Space))

DllCall(&XOR_Stream, "uint",&a, "uint",&b, "uint",StrLen(a))
MsgBox % a
DllCall(&XOR_Stream, "uint",&a, "uint",&b, "uint",StrLen(a))
MsgBox % a


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
It is OK, but I'd like it more like this
EXPORT void XOR_Stream_2(unsigned char* res, unsigned char* a, unsigned char* b, long len) { 
  for(long i=0; i<len; ++i)  res[i] = a[i] ^ b[i];  }
It has byte resolution and the result could be saved in a third array, which can be the same as a or b, if you want to overwrite one.

olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005

EXPORT void XOR_Stream_2(unsigned char* res, unsigned char* a, unsigned char* b, long len) { 

  for(long i=0; i<len; ++i)  res[i] = a[i] ^ b[i];  }

Here it is:
#NoEnv



MCode(XOR_ByteStream, "5589E583EC04C745FC000000008B45FC3B45147D248B45088"

. "B4DFC01C18B450C8B55FC01C28B45100345FC0FB600320288018D45FCFF00EBD4C9C3")



a := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 

VarSetCapacity(b, StrLen(a), Asc(A_Space))

VarSetCapacity(res, StrLen(a))

DllCall(&XOR_ByteStream, "uint",&res, "uint",&a, "uint", &b, "uint",StrLen(a))

MsgBox % res


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Thanks! Also, your example code flips the case of (English) letters, what one could use to fix texts typed with the CapsLock key accidentally activated. Nice!

ahklerner
  • Members
  • 1386 posts
  • Last active: Oct 08 2014 10:29 AM
  • Joined: 26 Jun 2006
Would calling a function in a dll be possible with this method?

such as this:

Syntax

BOOL IsWindowVisible(      
        HWND hWnd
    );

Parameters
hWnd
[in] Handle to the window to test.

Return Value
If the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style, the return value is nonzero. Otherwise, the return value is zero.
Because the return value specifies whether the window has the WS_VISIBLE style, it may be nonzero even if the window is totally obscured by other windows.

Remarks
The visibility state of a window is indicated by the WS_VISIBLE style bit. When WS_VISIBLE is set, the window is displayed and subsequent drawing into it is displayed as long as the window has the WS_VISIBLE style.
Any drawing to a window with the WS_VISIBLE style will not be displayed if the window is obscured by other windows or is clipped by its parent window.

Function Information
Minimum DLL Version user32.dll
Header Declared in Winuser.h, include Windows.h
Import library User32.lib
<!-- m -->http://msdn2.microso...y/ms633530.aspx<!-- m -->

I can think of some uses for this.
Posted Image
ʞɔпɟ əɥʇ ʇɐɥʍ

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
why cant you just use it in ahk?

SetTitleMatchMode, 2
WinGet, ID, ID, AutoHotkey Help
Msg := DllCall("IsWindowVisible", UInt, ID)
MsgBox, ID: %ID% `nVisible: %Msg%


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I guess IsWindowVisible was just an example.

If you want to call a dll function from within a machine code function, you probably need some extra system calls (like "LoadLibrary", which loads the desired function into memory, and then search for the address of the function). I have not tried, but it should be possible. A simpler solution could be to break up the machine code to stand alone pieces and use AHK's dllcall in between to call the needed external functions.

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007

I guess IsWindowVisible was just an example.


oh yes...of course. im not sure i undertsand your explanation of how to perform the function.

it would be nice if ahk could also handle C code being written directly to it, similar to calling assembler within C++, so you could do something similar to

__asm
{
   mov al, 2
   mov dx, 0xD007
   out dx, al
}

in C++ and could do

_C
{
}

i would love this, as then you can have all the benefits of ahk (simple coding and easy to create guis etc) but you can have all the power of C without having to use workarounds

ahklerner
  • Members
  • 1386 posts
  • Last active: Oct 08 2014 10:29 AM
  • Joined: 26 Jun 2006
I was kind of thinking it would be faster than even using dll call directly.
Sort of how this:
; Example: This is a working script that writes some text to a file then reads it back into memory (requires v1.0.34+).
; This method can be used to help performance in cases where multiple files are being read or written simultaneously.

FileSelectFile, FileName, S16,, Create a new file:
if FileName =
    return
GENERIC_WRITE = 0x40000000  ; Open the file for writing rather than reading.
CREATE_ALWAYS = 2  ; Create new file (overwriting any existing file).
hFile := DllCall("CreateFile", str, FileName, Uint, GENERIC_WRITE, Uint, 0, UInt, 0, UInt, CREATE_ALWAYS, Uint, 0, UInt, 0)
if not hFile
{
    MsgBox Can't open "%FileName%" for writing.
    return
}
TestString = This is a test string.`r`n  ; When writing a file this way, use `r`n rather than `n to start a new line.
DllCall("WriteFile", UInt, hFile, str, TestString, UInt, StrLen(TestString), UIntP, BytesActuallyWritten, UInt, 0)
DllCall("CloseHandle", UInt, hFile)  ; Close the file.
Is faster than this:
FileAppend, This is a test string.`n, %FileName%
When used in a loop.

Would it be even faster (or even possible) to create machine code to do the following:
GENERIC_WRITE = 0x40000000  ; Open the file for writing rather than reading.
CREATE_ALWAYS = 2  ; Create new file (overwriting any existing file).
hFile := DllCall("CreateFile", str, FileName, Uint, GENERIC_WRITE, Uint, 0, UInt, 0, UInt, CREATE_ALWAYS, Uint, 0, UInt, 0)
if not hFile
    return 0
TestString = This is a test string.`r`n  ; When writing a file this way, use `r`n rather than `n to start a new line.
DllCall("WriteFile", UInt, hFile, str, TestString, UInt, StrLen(TestString), UIntP, BytesActuallyWritten, UInt, 0)
DllCall("CloseHandle", UInt, hFile)  ; Close the file.
return 1
:?:
Posted Image
ʞɔпɟ əɥʇ ʇɐɥʍ

olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005
2ahklerner:

Using machine code functions makes most sense when doing low level bit manipulations and\or when doing many loops, like in encryption routines.
Example: To encrypt 10MB of data with a cipher that works on 64bit (8byte) block and uses 64 rounds you need almost 84 million loops.

You can test how long alone the loops would take in AHK:
StartTime := A_TickCount
Loop, 84000000
{
  i++
}
ElapsedTime := A_TickCount - StartTime
MsgBox,  %ElapsedTime% milliseconds have elapsed.


olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005
CRC-32:
#NoEnv

SetFormat, Integer, Hex

MCode(ByRef code, hex) { ; allocate memory and write Machine Code there
   VarSetCapacity(code,StrLen(hex)//2)
   Loop % StrLen(hex)//2
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char")
}

MCode(CRC32_Init, "5589E583EC10C745FC2083B8EDC745F400000000817DF4FF0000007F508B45F48945F8C745F008000000837DF0007E238B45F88"
. "3E00185C0740D8B45F8D1E83345FC8945F8EB058D45F8D1288D45F0FF08EBD78B45F48D0C85000000008B55088B45F88904118D45F4FF00EBA7C9C3")
MCode(CRC32_Get, "5589E583EC04C745FC000000008B45FC3B450C732E8B45080345FC0FB60033451425FF0000008D0C85000000008B55108B4514C1"
. "E8083304118945148D45FCFF00EBCA8B4514C9C3")

VarSetCapacity(CRC32LookupTable, 256*4) 
DllCall(&CRC32_Init, "uint",&CRC32LookupTable) 

data = ABCDEFGHIJKLMNOPQRSTUVWXYZ ; ABF77822
GoSub, Calc
list .= res . a_tab . data . "`n"

data = 123456789 ; CBF43926
GoSub, Calc
list .= res . a_tab . data . "`n"

data = Automation. Hotkeys. Scripting. ; A3A82EF4
GoSub, Calc
list .= res . a_tab . data . "`n"

data = AutoHotkey ; 14C70CF9
GoSub, Calc
list .= res . a_tab . data . "`n"

data = abcdefghijklmnopqrstuvwxyz ; 4C2750BD
GoSub, Calc
list .= res . a_tab . data . "`n"

MsgBox % list

Calc:
res := DllCall(&CRC32_Get, "uint",&data, "uint",StrLen(data), "uint",&CRC32LookupTable, "uint",0xFFFFFFFF)  
res := res < 0 ? Abs(res) - 1 : ~res
StringUpper, res, res 
StringReplace, res, res, 0X, 0000000 
res := SubStr(res, -7)
return

C Code:
EXPORT void CRC32_Init(ulong* table) {  
  ulong poly = 0xEDB88320, CRC;
 
  for(int i = 0; i < 256; i++)
  {
    CRC = i;
    for(int j = 8; j > 0; j--)
    {
      if(CRC & 1)
        CRC = (CRC >> 1) ^ poly;
      else
        CRC >>= 1;
    }
      table[i] = CRC;
  }
}


EXPORT ulong CRC32_Get(uchar* buffer, ulong len, ulong* table, ulong crc32val) {
  //ulong crc32val = 0xFFFFFFFF;

  for (ulong i = 0;  i < len;  i ++) {
    crc32val = table[(crc32val ^ buffer[i]) & 0x000000FF] ^ (crc32val >> 8);
  }
  return crc32val;
}

Edit 20070929: Changed C code to accept start value as a parameter (useful when processing chunks of data)