ROR13 — And Its Linkage to API Calls within Modules

ROR13 (rotate right 13) is not a cryptographic hash, but it can be used to take strings of any length, and convert them into an integer…

ROR13 — And Its Linkage to API Calls within Modules

ROR13 (rotate right 13) is not a cryptographic hash, but it can be used to take strings of any length, and convert them into an integer value. It is used within executable code to generate an address to an API function within a DLL. The developer, though, must make sure there is no collisions with other functions in other modules. With ROR13 we take each 8-bit character and then convert to a Unicode value (with 16 bits). The result is a 32-bit integer value, and which is used as the address for the API function call. For each character, we then rotate the bits right by thirteen places:

dword >> 13 | dword << (32 - 13)) & 0xFFFFFFFF

For “Load” we get value is 0xE124D840:

python ror13.py test Load
Module: test
Function: Load
ROR13 Hash: 0x927810A
Module ROR13 hash: 0x2802A8CA
Function ROR13 hash: 0xE124D840

We can see in the following, that the return from a function is defined with a hex address of 0xA779563A (and which is put on the stack before another call to a function (here):

For this we have a module of wininel.dll and a function of “InternetOpenA”, and which has the return address of:

push 0xA779563A        ; hash( "wininet.dll", "InternetOpenA" )

The notation we often use for this is “wininet.dll!InternetOpenA”. If we try the program, we get:

Module:		 wininet.dll
Function: InternetOpenA
ROR13 Hash: 0xa779563a
Module ROR13 hash: 0x862e96f8
Function ROR13 hash: 0x214abf42

The following is the code:

# Some code extracted from https://github.com/iagox86/nbtool/blob/master/samples/shellcode-win32/hash.py
import sys
def ror(dword, bits):
return (dword >> bits | dword << (32 - bits)) & 0xFFFFFFFF
def unicode( string, uppercase=True ):
result = "";
if uppercase:
string = string.upper()
for c in string:
result += c + "\x00"
return result
def hash( module, function, bits=13):
module_hash = 0
function_hash = 0
for c in unicode( module + "\x00" ):
module_hash = ror( module_hash, bits )
module_hash += ord( c )
for c in str( function + "\x00" ):
function_hash = ror( function_hash, bits )
function_hash += ord( c )
h = module_hash + function_hash & 0xFFFFFFFF
return h

module="wininet.dll"
function="InternetOpenA"
if (len(sys.argv)>1):
module=str(sys.argv[1])
if (len(sys.argv)>2):
function=str(sys.argv[2])
print("== ROR13 hash ===\n")
print("Module:\t\t\t",module)
print("Function:\t\t",function)
print('Module ROR13 hash:\t0x%X' % hash(module,""))
print('Function ROR13 hash:\t0x%X' % hash("",function))
print('ROR13 Hash:\t\t0x%X' % hash(module,function))

Some well-known hashes include the ones from the ws2_32.dll library, and are related to the networking functions of bind, listen, accept, closesocket, connect, recv and send [here]:

( 0x6737DBC2, "ws2_32.dll!bind" ),                                             ( 0xFF38E9B7, "ws2_32.dll!listen" ),                                             ( 0xE13BEC74, "ws2_32.dll!accept" ),                                             ( 0x614D6E75, "ws2_32.dll!closesocket" ),                                             ( 0x6174A599, "ws2_32.dll!connect" ),                                             ( 0x5FC8D902, "ws2_32.dll!recv" ),                                             ( 0x5F38EBC2, "ws2_32.dll!send" ),

We can test the bind function with:

== ROR13 hash ===
Module:    ws2_32.dll
Function: bind
Module ROR13 hash: 0x9211A042
Function ROR13 hash: 0xD5263B80
ROR13 Hash: 0x6737DBC2

We thus need to make sure we do not have collisions in the API calls that we make for other function calls within modules.