Download VAC Reverse Engineering IDA Scripts

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

c5

Kim Kong Trasher
Dank Tier VIP
Dank Tier Donator
Jul 19, 2012
1,187
12,638
76
I'm kindly sharing a part of my VAC reversing scripts collection.

Those scripts are to be used with IDA + IDAPython, what they do is pretty self explanatory.. For those who still don't understand, the scripts are used to assist reversing of VAC modules, more precisely they: Rebuild/Fix VACs imports, Decrypt encrypted VAC stringtables and strings.


DecryptStr.py
C++:
# Name: DecryptStr.py
# Desc: Decrypt an encrypted VAC3 string at cursor and rename all the refs to it (point the cursor to the start of raw encrypted string data)
# Author: c5 (guidedhacking.com)

import idautils
import idaapi

xorKey = 0x55

# Get cursor address
ea = ScreenEA()

isValid = True
#verify if this could actually be a string
if Byte(ea) == xorKey :
	Message("\nError, invalid string\n")
	isValid = False
	
strLen = Byte(ea) ^ xorKey

if strLen > 48 or strLen <= 0 :
	Message("\nError, invalid string\n")
	isValid = False
	
if isValid == True :
	print("string address: %X" % ea)

	#decrypt string
	strPlaintext = ""
	for i in range(1, strLen + 1) :
		strPlaintext += (chr(Byte(ea + i) ^ xorKey))
		xorKey = Byte(ea + i)
		
	print("string: %s" % strPlaintext)

	#rename string
	MakeName(ea, "_str_" + strPlaintext)

	#find all refsto the string and rename them
	refCount = 0
	for xref in XrefsTo(ea, 0) :
		refCount += 1
		MakeName(xref.frm, "str_" + strPlaintext + str(refCount))

DecryptImportStringtable.py
C++:
# Name: DecryptImportStringtable.py
# Desc: Decrypt all encrypted VAC3 strings in a table pointed to by cursor and rename references to them (point cursor at encrypted string table first element (table with array of pointers to raw encrpyted strings))
# Author: c5 (guidedhacking.com)

import idautils
import idaapi

mainXorKey = 0x55

def DecryptStrAndRenameRefs(stringStart) :
	xorKey = mainXorKey
	ea = stringStart
	
	#verify if this could actually be a string
	if Byte(ea) == xorKey :
		return 0
		
	strLen = Byte(ea) ^ xorKey
	
	if strLen > 48 or strLen <= 0 :
		return 0
			
	#decrypt string
	strPlaintext = ""
	for i in range(1, strLen + 1) :
		strPlaintext += (chr(Byte(ea + i) ^ xorKey))
		xorKey = Byte(ea + i)
		
	#rename string
	MakeName(ea, "_str_" + strPlaintext)
	
	#find all refsto the string and rename them
	refCount = 0
	for xref in XrefsTo(ea, 0) :
		refCount += 1
		MakeName(xref.frm, "str_" + strPlaintext + str(refCount))
	return 1

		
# Get cursor address
tableStart = ScreenEA()

tableItemsCount = 0
currentTableItem = tableStart
while (tableItemsCount < 128) : #some sanity
	if Dword(currentTableItem) == 0 :
		break
	
	if (DecryptStrAndRenameRefs(Dword(currentTableItem)) == 0) :
		break
	
	currentTableItem += 4
	tableItemsCount += 1

print("\nTable renamed (%i strings)\n" % tableItemsCount)

FixMainImportTables.py
C++:
# Name: FixMainImportTables.py
# Desc: Finds all main imported functions loaded during initialization and renames pointers to them. If a function is "ref'ed to", a __ endix is appended to the name (that usually means this function is directly called)
# Author: c5 (guidedhacking.com)

import idautils
import idaapi

start = 0x10001000
end = 0x10060000
		
mainXorKey = 0x55
loadModuleImportsPat1 = [0x56, 0x8B, 0x74, 0x24, 0x0C, 0x83, 0x3E, 0x00, 0x75, 0x04, 0x32, 0xC0, 0x5E, 0xC3]
loadModuleImportsMask1 = "xxxxxxxxx?xxxx"	

loadModuleImportsPat2 = [0x55, 0x8B, 0xEC, 0x53, 0x8B, 0x5D, 0x0C, 0x8B, 0x03, 0x56, 0x33, 0xF6, 0x3B, 0xC6, 0x75, 0x04, 0x32, 0xC0]
loadModuleImportsMask2 = "xxxxxxxxxxxxxxx?xx"	


def DecryptStr(stringStart) :
	xorKey = mainXorKey
	ea = stringStart
	
	#verify if this could actually be a string
	if Byte(ea) == xorKey :
		return 0
		
	strLen = Byte(ea) ^ xorKey
	
	if strLen > 48 or strLen <= 0 :
		return 0
			
	#decrypt string
	strPlaintext = ""
	for i in range(1, strLen + 1) :
		strPlaintext += (chr(Byte(ea + i) ^ xorKey))
		xorKey = Byte(ea + i)
		
	return strPlaintext
	
def findPattern(current, pat, mask) :
	Index = 0
	for x in pat :
		if mask[Index] == "?" :
			Index += 1
			continue
		if x != Byte(current + Index) :
			return 0
		else :
			Index += 1
	return current
	
# find LoadModuleImports
n = start
found = False
while n < end :
	if findPattern(n, loadModuleImportsPat1, loadModuleImportsMask1) != 0 :
		print("\nLoadModuleImports: 0x%x" % n)
		found = True
		break
	n += 1

if (found == False) :
	n = start
	while n < end :
		if findPattern(n, loadModuleImportsPat2, loadModuleImportsMask2) != 0 :
			print("\nLoadModuleImports: 0x%x" % n)
			found = True
			break
		n += 1
	
loadModImports = n	
funcNamesPatched = 0
if found == True :
	for ref in CodeRefsTo(loadModImports, False):
		# 68 C8 EF 00 10      push    offset str_ntdll_dll1
		# 68 1C 45 41 10      push    offset hNtdll
		# E8 AE FC FF FF      call    LoadModuleImports	
		stringTableStart = Dword(ref - 9)
		funcTableStart = Dword(ref - 4)
		
		print("Module:    %s " % DecryptStr(Dword(stringTableStart)))
		print("Functions: %X " % funcTableStart)
		# iterate current stringtable
		currentItemCount = 0		
		currentStringTableItem = stringTableStart + 4 #first item is handle to module
		while (currentItemCount < 128) :
			if Dword(currentStringTableItem) == 0 :
				break
			
			decryptedFuncName = DecryptStr(Dword(currentStringTableItem))
			if (decryptedFuncName == 0) :
				break
			
			# rename functable item
			currentFuncPtrItem = funcTableStart + 4 + (4 * currentItemCount)
			
			#print("%X " % currentFuncPtrItem)
			#print("%s " % decryptedFuncName)
			MakeDword(currentFuncPtrItem)
			
			funcName = "pFn" + decryptedFuncName

			refCount = 0
			for xref in XrefsTo(currentFuncPtrItem, 0) :
				refCount += 1
				
			if refCount > 0 :
				funcName += "__"
			
			MakeName(currentFuncPtrItem, funcName)
			
			# next iteration
			currentStringTableItem += 4
			currentItemCount += 1
			
		funcNamesPatched += currentItemCount
	print("%i function pointers renamed\n" % funcNamesPatched)
else :
	print("Failed\n")

 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,164
78,998
2,399
you just headshot 90% of guidedhacking members with this post, including me
 

Obsta

Jr.Hacker
Meme Tier VIP
Jan 27, 2014
394
4,338
17
[GH] Rake;35396 said:
you just headshot 90% of guidedhacking members with this post, including me
90% is a bit of a understatement, 98%, 99% might be more accurate.
 

c5

Kim Kong Trasher
Dank Tier VIP
Dank Tier Donator
Jul 19, 2012
1,187
12,638
76
Oh come on guys, it's not that bad. The amount of people who go more in depth is just smaller here, maybe this helps some lead the way. VAC isn't exactly easy to reverse but it's not anything super godlike hard either. Back to the point, game hacking is far from just employing Cheat Engine and writing trainers (which can be of course fun, but for the sake of a challenge, go further!), I'd like to see more and more users here who post sophisticated information, findings and journeys :)
 

keto

Dank Tier Donator
Nobleman
May 25, 2013
151
1,648
1
Oh come on guys, it's not that bad. The amount of people who go more in depth is just smaller here, maybe this helps some lead the way. VAC isn't exactly easy to reverse but it's not anything super godlike hard either. Back to the point, game hacking is far from just employing Cheat Engine and writing trainers (which can be of course fun, but for the sake of a challenge, go further!), I'd like to see more and more users here who post sophisticated information, findings and journeys :)
I agree. If I only wouldn't be that lazy, lol...
 

c5

Kim Kong Trasher
Dank Tier VIP
Dank Tier Donator
Jul 19, 2012
1,187
12,638
76
Another small cookie. Finds the scan functions array with a sig based 'meh' approach.

C++:
# Name: FindScangates.py
# Desc: Finds all main scangates from the call array
# Author: c5 (guidedhacking.com)

import idautils
import idaapi

start = 0x10001000
end = 0x10060000
		
		
#68 ?? ?? ?? ?? B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? C3   		
initScanGatePat1 = [0x68, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xC3]
initScanGateMask1 = "x????x????x????x"	
	
def findPattern(current, pat, mask) :
	Index = 0
	for x in pat :
		if mask[Index] == "?" :
			Index += 1
			continue
		if x != Byte(current + Index) :
			return 0
		else :
			Index += 1
	return current
	
# find all scangate funcs
print("\nLooking for scan gates..")
n = start
found = 0
while n < end :
	if findPattern(n, initScanGatePat1, initScanGateMask1) != 0 :
		# 68 08 B0 00 10  push    offset scan_gate1
		# B9 31 C0 00 10  mov     ecx, offset unk_1000C031
		# E8 09 17 00 00  call    init_gate
		gate = Dword(n + 1)
		found += 1
		funcName = "scan_gate_" + str(found)
		print("\nFound gate at 0x%X" % gate)
		MakeName(gate, funcName)
	n += 1
print("\nFound: %i scan gates" % found)
 
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods