├── EncryptString ├── BeepBox-Song.wav ├── EncryptString.fsproj └── Program.fs ├── old_crackme ├── CrackMe#1 pwd crackmes.de.zip └── s4tanic0de pwd crackmes.de.zip ├── Src ├── s4tanic0d3.user ├── s4tanic0d3.vcxproj.user ├── s4tanic0d3.filters ├── model.inc ├── validator.inc ├── console.inc ├── s4tanic0d3.vcxproj ├── utility.inc ├── main.asm ├── obfuscation.inc └── rubik_cube.inc ├── x64Check ├── x64Check.vcxproj.user ├── main.asm ├── x64Check.vcxproj.filters └── x64Check.vcxproj ├── .gitignore ├── README.md ├── obfuscate.py ├── s4tanic0d3.sln └── LICENSE /EncryptString/BeepBox-Song.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkomio/s4tanic0d3/HEAD/EncryptString/BeepBox-Song.wav -------------------------------------------------------------------------------- /old_crackme/CrackMe#1 pwd crackmes.de.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkomio/s4tanic0d3/HEAD/old_crackme/CrackMe#1 pwd crackmes.de.zip -------------------------------------------------------------------------------- /old_crackme/s4tanic0de pwd crackmes.de.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkomio/s4tanic0d3/HEAD/old_crackme/s4tanic0de pwd crackmes.de.zip -------------------------------------------------------------------------------- /Src/s4tanic0d3.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Src/s4tanic0d3.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /x64Check/x64Check.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /x64Check/main.asm: -------------------------------------------------------------------------------- 1 | .code 2 | 3 | main proc 4 | ; do check with ESI register 5 | mov rax, gs:[30h] 6 | mov rax, [rax+60h] 7 | movzx rax, byte ptr [rax+2h] 8 | test rax, rax 9 | mov rbx, 0baadc0deh 10 | mov rax, 0cafebabeh 11 | cmove rbx, rax 12 | xor rsi, rbx 13 | 14 | ; move back to 32 bit 15 | call $+5 16 | mov DWORD PTR [rsp+4h], 23h 17 | add DWORD PTR [rsp], 0Dh 18 | retf 19 | main endp 20 | 21 | end -------------------------------------------------------------------------------- /EncryptString/EncryptString.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | Always 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | Debug 3 | Release 4 | bin 5 | packages/ 6 | obj/ 7 | .fake/ 8 | fake/ 9 | 10 | # Prerequisites 11 | *.d 12 | 13 | # Object files 14 | *.o 15 | *.ko 16 | *.obj 17 | *.elf 18 | *.cache 19 | 20 | # Linker output 21 | *.ilk 22 | *.map 23 | *.exp 24 | 25 | # Precompiled Headers 26 | *.gch 27 | *.pch 28 | 29 | # Libraries 30 | *.lib 31 | *.a 32 | *.la 33 | *.lo 34 | 35 | # Shared objects (inc. Windows DLLs) 36 | *.dll 37 | *.so 38 | *.so.* 39 | *.dylib 40 | 41 | # Executables 42 | *.exe 43 | *.out 44 | *.app 45 | *.i*86 46 | *.x86_64 47 | *.hex 48 | 49 | # Debug files 50 | *.dSYM/ 51 | *.su 52 | *.idb 53 | *.pdb 54 | 55 | # Kernel Module Compile Results 56 | *.mod* 57 | *.cmd 58 | .tmp_versions/ 59 | modules.order 60 | Module.symvers 61 | Mkfile.old 62 | dkms.conf 63 | -------------------------------------------------------------------------------- /x64Check/x64Check.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /Src/s4tanic0d3.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # s4tanic0d3 2 | After more than 10 years I decided to write a new Crackme challenge. The binary contains some tricks, with some revivals from old sk00l era :) If you find it interesting and you want to write a tutorial, I'll be happy to add the link to your tutorial in this page. Enjoy! 3 | 4 | If you think to have find a bug, please open an issue or send me a DM on twitter: https://twitter.com/s4tan 5 | 6 | ## Requirements 7 | The program runs only on 64-bit systems 8 | 9 | ## Description 10 | Difficulty: **Hard** 11 | 12 | You can download the binary from: https://github.com/enkomio/s4tanic0d3/releases/tag/1.0 13 | 14 | SHA-1: 3F73CF764F1E84DECCF85B902C71722D2230A0C5 15 | 16 | #### Valid ID/License: 17 | ID: s4tan 18 | 19 | License: cc144ggc057cc4402dgg44gg66cc22 20 | 21 | ID: antani 22 | 23 | License: 0c2h7h35g66gg4600446gg66003 24 | 25 | Here is a link to the crackme ending screen :) 26 | 27 | ### Goals: 28 | * Find a valid ID/License pair 29 | * Write a license generator 30 | 31 | ### Solutions 32 | * Blind solving a crackme by s4tan - Part 1, by: ZetaTwo 33 | * Blind solving a crackme by s4tan - Part 2, by: ZetaTwo 34 | * Blind solving a crackme by s4tan - Part 3, by: ZetaTwo 35 | 36 | #### Updates: 37 | * 2020/11/20 - Source code released 38 | * 2020/10/30 - Updated binary to fix an issue in case of invalid license 39 | -------------------------------------------------------------------------------- /Src/model.inc: -------------------------------------------------------------------------------- 1 | 2 | ; import 3 | VirtualProtect proto, lpAddress:ptr dword, dwSize:dword, flNewProtect:dword, lpflOldProtect:ptr dword 4 | CloseHandle proto, nStdHandle:dword 5 | GetStdHandle proto, nStdHandle:dword 6 | WriteConsoleA proto, hConsoleInput:dword, lpBuffer:ptr byte, nNumberOfCharsToWrite:dword, lpNumberOfCharsWritten:ptr dword, lpReserved:dword 7 | ReadConsoleA proto, hConsoleInput:dword, lpBuffer:ptr byte, nNumberOfCharsToRead:dword, lpNumberOfCharsRead:ptr dword, pInputControl:ptr dword 8 | SetConsoleMode proto, hConsoleHandle:dword, dwMode:dword 9 | GetConsoleMode proto, hConsoleHandle:dword, lpMode:ptr dword 10 | GetLastError proto 11 | mciSendCommandA proto, IDDevice:dword, uMsg:dword, fdwCommand:ptr dword, dwParam:ptr dword 12 | mmioInstallIOProcA proto fccIOProc:dword, pIOProc:ptr dword, dwFlags:dword 13 | Sleep proto dwMilliseconds:dword 14 | ExitProcess proto uExitCode:dword 15 | 16 | EXCEPTION_SINGLE_STEP equ 80000004h 17 | EXCEPTION_PRIVILEGED_INSTRUCTION equ 0C0000096h 18 | PAGE_EXECUTE_READWRITE equ 00000040h 19 | STD_INPUT_HANDLE equ -10 20 | STD_OUTPUT_HANDLE equ -11 21 | 22 | ; helpful constants 23 | arg0 equ 8h 24 | arg1 equ 0Ch 25 | arg2 equ 10h 26 | arg3 equ 14h 27 | 28 | local0 equ -4h 29 | local1 equ -8h 30 | local2 equ -0Ch 31 | local3 equ -10h 32 | local4 equ -14h 33 | local5 equ -18h 34 | local6 equ -1Ch 35 | local7 equ -20h 36 | 37 | ; marker to identify protected code 38 | marker_1 equ 1ce1c3bbh 39 | marker_2 equ 0c0deca05h 40 | marker_3 equ 0deadc0deh 41 | marker_4 equ 0cafebabeh 42 | shuffle_mark equ 43 | start_protected_code_marker equ 44 | end_protected_code_marker equ 45 | 46 | CONTEXT struct 47 | ContextFlags DWORD ? 48 | rDr0 DWORD ? 49 | rDr1 DWORD ? 50 | rDr2 DWORD ? 51 | rDr3 DWORD ? 52 | rDr6 DWORD ? 53 | rDr7 DWORD ? 54 | ControlWord DWORD ? 55 | StatusWord DWORD ? 56 | TagWord DWORD ? 57 | ErrorOffset DWORD ? 58 | ErrorSelector DWORD ? 59 | DataOffset DWORD ? 60 | DataSelector DWORD ? 61 | RegisterArea dt 8 dup (?) 62 | Cr0NpxState DWORD ? 63 | 64 | SegGs DWORD ? 65 | SegFs DWORD ? 66 | SegEs DWORD ? 67 | SegDs DWORD ? 68 | 69 | rEdi DWORD ? 70 | rEsi DWORD ? 71 | rEbx DWORD ? 72 | rEdx DWORD ? 73 | rEcx DWORD ? 74 | rEax DWORD ? 75 | 76 | rEbp DWORD ? 77 | rEip DWORD ? 78 | SegCs DWORD ? 79 | EFlags DWORD ? 80 | rEsp DWORD ? 81 | SegSs DWORD ? 82 | 83 | ExtendedRegisters db 512 dup (?) 84 | CONTEXT ends 85 | 86 | MCI_OPEN_PARMS struct 87 | dwCallback dword ptr ? 88 | wDeviceID dword ? 89 | lpstrDeviceType dword ptr? 90 | lpstrElementName dword ptr ? 91 | lpstrAlias dword ptr ? 92 | MCI_OPEN_PARMS ends 93 | 94 | MCI_PLAY_PARMS struct 95 | dwCallback dword ptr ? 96 | dwFrom dword ? 97 | dwTo dword ? 98 | MCI_PLAY_PARMS ends 99 | 100 | MMIOINFO struct 101 | dwFlags dword ? 102 | fccIOProc dword ? 103 | pIOProc dword ptr ? 104 | wErrorRet dword ? 105 | htask dword ptr ? 106 | cchBuffer dword ? 107 | pchBuffer dword ptr ? 108 | pchNext dword ptr ? 109 | pchEndRead dword ptr ? 110 | pchEndWrite dword ptr ? 111 | lBufOffset dword ? 112 | lDiskOffset dword ? 113 | adwInfo dword 3 dup (?) 114 | dwReserved1 dword ? 115 | dwReserved2 dword ? 116 | hmmio dword ptr ? 117 | MMIOINFO ends -------------------------------------------------------------------------------- /obfuscate.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | with open(sys.argv[1], 'rb') as f: 5 | c = f.read() 6 | 7 | start_mark = b"\xbb\xc3\xe1\x1c\x05\xca\xde\xc0\xde\xc0\xad\xde\xbe\xba\xfe\xca" 8 | end_mark = b"\xbe\xba\xfe\xca\xde\xc0\xad\xde\x05\xca\xde\xc0\xbb\xc3\xe1\x1c" 9 | start = c.find(start_mark) + len(start_mark) 10 | end = c.find(end_mark) 11 | 12 | rol = lambda val, r_bits, max_bits: \ 13 | (val << r_bits % max_bits) & (2 ** max_bits - 1) | \ 14 | ((val & (2 ** max_bits - 1)) >> (max_bits - (r_bits % max_bits))) 15 | 16 | ror = lambda val, r_bits, max_bits: \ 17 | ((val & (2 ** max_bits - 1)) >> r_bits % max_bits) | \ 18 | (val << (max_bits - (r_bits % max_bits)) & (2 ** max_bits - 1)) 19 | 20 | DEBUG = False 21 | 22 | def gen_rand(i): 23 | if DEBUG: 24 | print('*************************') 25 | print('Addr: ' + hex(i)) 26 | a = (65793 * (i & 0xff)) & 0xffffffff 27 | if DEBUG: 28 | print('A: ' + hex(a)) 29 | r = (a + 4282663) & 0xffffffff 30 | if DEBUG: 31 | print('B: ' + hex(r)) 32 | counts = bin(r).count("1") 33 | if DEBUG: 34 | print('Num of bits: ' + hex(counts)) 35 | if i % 2 == 0: 36 | r = rol(r, counts, 8) 37 | if DEBUG: 38 | print('Result (ROL): ' + hex(r)) 39 | else: 40 | r = ror(r, counts, 8) 41 | if DEBUG: 42 | print('Result (ROR): ' + hex(r)) 43 | r = r % 0xa 44 | if DEBUG: 45 | print('Result mod 0xA: ' + hex(r)) 46 | return r 47 | 48 | def obf0(b, addr): 49 | return b ^ 0xcc 50 | 51 | def obf1(b, addr): 52 | return (b + 0xaa) & 0xff 53 | 54 | def obf2(b, addr): 55 | nb = (b - 0x42) & 0xff 56 | nb = rol(nb, 2, 8) 57 | return nb 58 | 59 | def obf3(b, addr): 60 | return b ^ (addr & 0xff) 61 | 62 | def obf4(b, addr): 63 | return (b + (addr & 0xff)) & 0xff 64 | 65 | def obf5(b, addr): 66 | return (b - (addr & 0xff)) & 0xff 67 | 68 | def obf6(b, addr): 69 | nb = ror(b, 4, 8) 70 | return ~nb & 0xff 71 | 72 | def obf7(b, addr): 73 | return (~b ^ 0x17) & 0xff 74 | 75 | def obf8(b, addr): 76 | return (~b ^ ~(addr & 0xff)) & 0xff 77 | 78 | def obf9(b, addr): 79 | n_addr = rol(addr, 6, 8) 80 | n_addr = (~n_addr) & 0xff 81 | nb = b ^ n_addr 82 | nb = rol(nb, 3, 8) 83 | return nb & 0xff 84 | 85 | # create routines list 86 | cl = list(c) 87 | routines = list() 88 | for i in range(10): 89 | routines.append((1, "obf" + str(i))) 90 | 91 | # obfuscated bytes 92 | original_bytes = "" 93 | obfuscated_bytes = "" 94 | for i in range(start, end): 95 | v = i & 0xFF 96 | type = gen_rand(v) 97 | 98 | # get the routine to executed 99 | for j in range(10): 100 | index = (type+j) % 10 101 | (enabled, routine) = routines[index] 102 | if enabled: 103 | routines[index] = (0, routine) 104 | break 105 | else: 106 | if DEBUG: 107 | print("Do wrap") 108 | for j in range(10): 109 | (enabled, tmp_routine) = routines[j] 110 | routines[j] = (1, tmp_routine) 111 | (enabled, routine) = routines[type] 112 | routines[type] = (0, routine) 113 | 114 | obf_b = locals()[routine](cl[i], i) 115 | if DEBUG: 116 | print("Addr 0x%x (rand: 0x%x), orig byte 0x%x, obfuscated byte 0x%x obfuscation routine: %s" % (v, type, cl[i], obf_b, routine)) 117 | cl[i] = obf_b 118 | 119 | c = bytearray(cl) 120 | file = os.path.basename(sys.argv[1]) 121 | dirname = os.path.dirname(sys.argv[1]) 122 | dest_file = os.path.join(dirname, 'obf_' + file) 123 | 124 | print("Start: 0x%x" % start) 125 | print("End: 0x%x" % end) 126 | 127 | with open(dest_file, 'wb') as f: 128 | f.write(c) -------------------------------------------------------------------------------- /EncryptString/Program.fs: -------------------------------------------------------------------------------- 1 | open System 2 | open System.Reflection 3 | open System.Text 4 | open System.IO 5 | 6 | let rc4(key: Byte array, data: Byte array) = 7 | let mutable S = [|for i in 0 .. 255 -> i|] 8 | 9 | // KSA 10 | let mutable j =0 11 | for i in 0..255 do 12 | j <- (j + S.[i] + int32(key.[i % key.Length])) % 256 13 | let mutable tmp = S.[i] 14 | S.[i] <- S.[j] 15 | S.[j] <- tmp 16 | 17 | // PRGA 18 | let mutable i = 0 19 | let mutable j = 0 20 | let result = Array.zeroCreate(data.Length) 21 | 22 | data 23 | |> Array.iteri(fun index b -> 24 | i <- (i + 1) % 256 25 | j <- (j + S.[i]) % 256 26 | 27 | // swap 28 | let mutable tmp = S.[i] 29 | S.[i] <- S.[j] 30 | S.[j] <- tmp 31 | 32 | let k = S.[(S.[i] + S.[j]) % 256] 33 | data.[index] <- data.[index] ^^^ byte k 34 | ) 35 | 36 | 37 | [] 38 | let main argv = 39 | let key = [|0xdeuy; 0xc0uy; 0x7auy; 0x5auy|] 40 | let greeting = """License valid! 41 | 42 | -=[ s4tanic0d3 ]=- 43 | 44 | BEING THE WISE AND COURAGEOUR 45 | 46 | KNIGHT THAT YOU ARE YOU 47 | 48 | FEEL STRONGTH WELLING 49 | 50 | IN YOUR BODY. 51 | 52 | Thank you for playing! 53 | 54 | -- 55 | (c) enkomio - 2020 56 | https://github.com/enkomio/s4tanic0d3 57 | """ 58 | 59 | let musicFileContent = 60 | Path.Combine( 61 | Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), 62 | "BeepBox-Song.wav" 63 | ) 64 | |> Path.GetFullPath 65 | |> File.ReadAllBytes 66 | 67 | // encrypt 68 | rc4(key, musicFileContent) 69 | let encGreeting = Encoding.ASCII.GetBytes(greeting) 70 | encGreeting.[encGreeting.Length - 1] <- 0uy 71 | rc4(key, encGreeting) 72 | 73 | // create file content 74 | let res = new StringBuilder() 75 | let mutable name = "g_sound " 76 | musicFileContent 77 | |> Array.chunkBySize 16 78 | |> Array.iteri(fun i chunk -> 79 | res.AppendFormat("{0}byte ", name) |> ignore 80 | name <- String.Empty 81 | let t = new StringBuilder() 82 | chunk 83 | |> Array.iter(fun b -> 84 | let s = String.Format("0{0}h, ", b.ToString("X")) 85 | t.Append(s) |> ignore 86 | ) 87 | 88 | res.AppendLine(t.ToString().Trim().Trim(',')) |> ignore 89 | ) 90 | 91 | res.AppendFormat("g_sound_size dword 0{0}h", musicFileContent.Length.ToString("X")) |> ignore 92 | res.AppendLine() |> ignore 93 | 94 | name <- "g_success " 95 | encGreeting 96 | |> Array.chunkBySize 16 97 | |> Array.iteri(fun i chunk -> 98 | res.AppendFormat("{0}byte ", name) |> ignore 99 | name <- String.Empty 100 | let t = new StringBuilder() 101 | chunk 102 | |> Array.iter(fun b -> 103 | let s = String.Format("0{0}h, ", b.ToString("X")) 104 | t.Append(s) |> ignore 105 | ) 106 | 107 | res.AppendLine(t.ToString().Trim().Trim(',')) |> ignore 108 | ) 109 | 110 | res.AppendLine() |> ignore 111 | res.AppendFormat("g_success_size dword 0{0}h", (encGreeting.Length - 1).ToString("X")) |> ignore 112 | 113 | // write file 114 | let resultFile = 115 | Path.Combine( 116 | Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), 117 | "..", 118 | "..", 119 | "..", 120 | "..", 121 | "Src", 122 | "media.inc" 123 | ) 124 | |> Path.GetFullPath 125 | File.WriteAllText(resultFile, res.ToString()) 126 | 0 127 | -------------------------------------------------------------------------------- /s4tanic0d3.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30406.217 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "s4tanic0d3", "Src\s4tanic0d3.vcxproj", "{31256678-83BF-446F-8598-B2B1B398B9EE}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EncryptString", "EncryptString\EncryptString.fsproj", "{B86568AB-7CCE-40D0-9053-8D33B0D0D262}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64Check", "x64Check\x64Check.vcxproj", "{EAD64984-A0DC-4384-9D34-C29C61DF12E7}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Debug|Any CPU.ActiveCfg = Debug|Win32 23 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Debug|x64.ActiveCfg = Debug|x64 24 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Debug|x64.Build.0 = Debug|x64 25 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Debug|x86.ActiveCfg = Debug|Win32 26 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Debug|x86.Build.0 = Debug|Win32 27 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Release|Any CPU.ActiveCfg = Release|Win32 28 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Release|x64.ActiveCfg = Release|x64 29 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Release|x64.Build.0 = Release|x64 30 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Release|x86.ActiveCfg = Release|Win32 31 | {31256678-83BF-446F-8598-B2B1B398B9EE}.Release|x86.Build.0 = Release|Win32 32 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Debug|x64.ActiveCfg = Debug|Any CPU 35 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Debug|x64.Build.0 = Debug|Any CPU 36 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Debug|x86.ActiveCfg = Debug|Any CPU 37 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Debug|x86.Build.0 = Debug|Any CPU 38 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Release|x64.ActiveCfg = Release|Any CPU 41 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Release|x64.Build.0 = Release|Any CPU 42 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Release|x86.ActiveCfg = Release|Any CPU 43 | {B86568AB-7CCE-40D0-9053-8D33B0D0D262}.Release|x86.Build.0 = Release|Any CPU 44 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Debug|Any CPU.ActiveCfg = Debug|Win32 45 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Debug|x64.ActiveCfg = Debug|x64 46 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Debug|x64.Build.0 = Debug|x64 47 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Debug|x86.ActiveCfg = Debug|Win32 48 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Debug|x86.Build.0 = Debug|Win32 49 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Release|Any CPU.ActiveCfg = Release|Win32 50 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Release|x64.ActiveCfg = Release|x64 51 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Release|x64.Build.0 = Release|x64 52 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Release|x86.ActiveCfg = Release|Win32 53 | {EAD64984-A0DC-4384-9D34-C29C61DF12E7}.Release|x86.Build.0 = Release|Win32 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | GlobalSection(ExtensibilityGlobals) = postSolution 59 | SolutionGuid = {F1423AF9-580E-4266-8C3A-36FD527A337A} 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /Src/validator.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Compute the initialization key to set the start state of rubik cube 3 | ; Parameter: expanded username 4 | ; 5 | compute_initialization_key proc 6 | push ebp 7 | mov ebp, esp 8 | 9 | mov esi, dword ptr [ebp+arg0] 10 | 11 | ; expand result 12 | vmovdqu xmm0, xmmword ptr [esi] 13 | vpsllw xmm1, xmm0, 4 14 | vpabsb xmm1, xmm1 15 | vpor xmm0, xmm1, xmm0 16 | vpbroadcastb xmm2, byte ptr [g_ascii_lower] 17 | vpxor xmm0, xmm0, xmm2 18 | 19 | ; compute max, min and sum 20 | vpxor xmm1, xmm1, xmm1 21 | vpunpcklbw xmm2, xmm0, xmm1 22 | vpunpckhbw xmm3, xmm0, xmm1 23 | vpmaxuw xmm4, xmm3, xmm2 24 | vpminuw xmm5, xmm3, xmm2 25 | vpaddusw xmm6, xmm3, xmm2 26 | 27 | vpsrldq xmm2, xmm4, 8 28 | vpsrldq xmm3, xmm5, 8 29 | vpsrldq xmm1, xmm6, 8 30 | vpmaxuw xmm4, xmm4, xmm2 31 | vpminuw xmm5, xmm5, xmm3 32 | vpaddusw xmm6, xmm6, xmm1 33 | 34 | vpsrldq xmm2, xmm4, 4 35 | vpsrldq xmm3, xmm5, 4 36 | vpsrldq xmm1, xmm6, 4 37 | vpmaxuw xmm4, xmm4, xmm2 38 | vpminuw xmm5, xmm5, xmm3 39 | vpaddusw xmm6, xmm6, xmm1 40 | 41 | vpsrldq xmm2, xmm4, 2 42 | vpsrldq xmm3, xmm5, 2 43 | vpsrldq xmm1, xmm6, 2 44 | vpmaxuw xmm4, xmm4, xmm2 45 | vpminuw xmm5, xmm5, xmm3 46 | vpaddusw xmm6, xmm6, xmm1 47 | 48 | ; extract info 49 | vpextrb ebx, xmm4, 0 50 | vpextrb ecx, xmm5, 0 51 | vpextrw eax, xmm6, 0 52 | shl eax, 8 53 | or eax, ecx 54 | shl eax, 8 55 | or eax, ebx 56 | rol eax, 13h 57 | 58 | mov esp, ebp 59 | pop ebp 60 | ret 61 | compute_initialization_key endp 62 | 63 | ; 64 | ; generate a random number used to initialize rubik cube. 65 | ; This function update the value of the seed 66 | ; Parameters: seed address 67 | ; 68 | gen_cube_random proc 69 | push ebp 70 | mov ebp, esp 71 | 72 | mov edi, dword ptr [ebp+arg0] 73 | mov eax, dword ptr [edi] 74 | 75 | mov edx, 0f1h 76 | mul edx 77 | add eax, 5a74c0d3h 78 | mov ebx, 12h 79 | xor edx, edx 80 | div ebx 81 | 82 | mov dword ptr [edi], eax 83 | mov eax, edx 84 | inc eax 85 | 86 | mov esp, ebp 87 | pop ebp 88 | ret 89 | gen_cube_random endp 90 | 91 | ; 92 | ; Shuffle the cube faces 93 | ; Parameter: init seed, cube faces buffer 94 | ; 95 | shuffle_cube proc 96 | push ebp 97 | mov ebp, esp 98 | sub esp, sizeof dword 99 | 100 | ; initialize loop counter 101 | mov dword ptr [ebp+local0], 100h 102 | 103 | @@: 104 | ; generate the random move to execute 105 | lea edi, [ebp+arg0] 106 | push edi 107 | nano_call n_gen_cube_random 108 | 109 | ; execute the move 110 | mov esi, dword ptr [ebp+arg1] 111 | push eax 112 | execute_move esi, eax 113 | pop eax 114 | 115 | dec dword ptr [ebp+local0] 116 | cmp dword ptr [ebp+local0], 0h 117 | ja @b 118 | 119 | mov esp, ebp 120 | pop ebp 121 | ret 122 | shuffle_cube endp 123 | 124 | ; 125 | ; Verify if the cube is in a completation state 126 | ; Parameter: the cube state 127 | ; Return: a DWORD representing the state of the cube 128 | ; 129 | verify_cube_result proc 130 | push ebp 131 | mov ebp, esp 132 | sub esp, sizeof dword 133 | 134 | xor ebx, ebx 135 | mov dword ptr [ebp+local0], 1h 136 | mov esi, dword ptr [ebp+arg0] 137 | mov ecx, 36h 138 | 139 | @@: 140 | mov eax, ecx 141 | xor edx, edx 142 | mov edi, 9h 143 | div edi 144 | test edx, edx 145 | jnz @do_computation 146 | test bl, bl 147 | jz @do_computation 148 | mov eax, dword ptr [ebp+local0] 149 | mul bl 150 | mov dword ptr [ebp+local0], eax 151 | 152 | @do_computation: 153 | mov al, byte ptr [esi] 154 | inc esi 155 | xor bl, al 156 | loop @b 157 | 158 | mov eax, dword ptr [ebp+local0] 159 | mov ebx, eax 160 | rol eax, 10h 161 | neg bx 162 | mov ax, bx 163 | xor eax, dword ptr [g_verification_magic] 164 | mov esp, ebp 165 | pop ebp 166 | ret 167 | verify_cube_result endp 168 | 169 | ; 170 | ; Check the received username and license key 171 | ; Parameters: Username and license key 172 | ; 173 | check_input proc 174 | push ebp 175 | mov ebp, esp 176 | sub esp, sizeof dword 177 | 178 | ; space for cube faces 179 | sub esp, 36h 180 | mov dword ptr [ebp+local0], esp 181 | 182 | ; set cube initial state 183 | mov ecx, 36h 184 | mov ebx, 0ffffffffh 185 | @@: 186 | ; compute current color 187 | mov eax, ecx 188 | xor edx, edx 189 | mov edi, 9h 190 | div edi 191 | test edx, edx 192 | jnz @write_color 193 | inc ebx 194 | 195 | @write_color: 196 | mov esi, ecx 197 | lea esi, [esi+esp-1] 198 | mov al, byte ptr [g_cube_color + ebx] 199 | mov byte ptr [esi], al 200 | loop @b 201 | 202 | ; compute initialization key 203 | push dword ptr [ebp+arg0] 204 | nano_call n_compute_initialization_key 205 | 206 | ; generate random cube state 207 | push dword ptr [ebp+local0] 208 | push eax 209 | nano_call n_shuffle_cube 210 | 211 | ; the cube is in its initial state. Execute the input moves 212 | mov eax, dword ptr [ebp+arg1] 213 | mov dword ptr [g_cube_moves], eax 214 | execute_next_move dword ptr [ebp+local0] 215 | 216 | ; check result and compute the decryption key 217 | push dword ptr [ebp+local0] 218 | nano_call n_verify_cube_result 219 | 220 | mov esp, ebp 221 | pop ebp 222 | ret 223 | check_input endp -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /Src/console.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Initialize console 3 | ; 4 | init_console proc 5 | push ebp 6 | mov ebp, esp 7 | 8 | ; set console mode to read just 1 character 9 | push STD_INPUT_HANDLE 10 | call GetStdHandle 11 | 12 | push 0a0h 13 | push eax 14 | call SetConsoleMode 15 | 16 | mov esp, ebp 17 | pop ebp 18 | ret 19 | init_console endp 20 | 21 | ; 22 | ; Write to console the input ASCII string 23 | ; Parameter: String to print 24 | ; 25 | print_line proc 26 | push ebp 27 | mov ebp, esp 28 | 29 | ; compute string length 30 | strlen (dword ptr [ebp+arg0]) 31 | 32 | push ecx 33 | push dword ptr [ebp+arg0] 34 | call print_buffer 35 | 36 | mov esp, ebp 37 | pop ebp 38 | ret 39 | print_line endp 40 | 41 | ; 42 | ; Write to console the input buffer 43 | ; Parameter: buffer to print, buffer size 44 | ; 45 | print_buffer proc 46 | push ebp 47 | mov ebp, esp 48 | sub esp, sizeof dword 49 | push ebx 50 | 51 | ; write string 52 | lea ebx, [ebp+local0] 53 | push 0 54 | push ebx 55 | push [ebp+arg1] 56 | push dword ptr [ebp+arg0] 57 | 58 | push STD_OUTPUT_HANDLE 59 | call GetStdHandle 60 | push eax 61 | 62 | call WriteConsoleA 63 | 64 | pop ebx 65 | mov esp, ebp 66 | pop ebp 67 | ret 68 | print_buffer endp 69 | 70 | ; 71 | ; Read line and return the string result 72 | ; Parameter: 73 | ; - a buffer that will contain the input characters 74 | ; - number of chars to read 75 | ; - a character as separator (can be null) 76 | ; - how many characters to read before to print the separator 77 | ; 78 | read_line proc 79 | push ebp 80 | mov ebp, esp 81 | sub esp, 5 * sizeof dword 82 | 83 | mov dword ptr [ebp+local4], 0h 84 | 85 | ; zero input buffer 86 | mov edi, dword ptr [ebp+arg0] 87 | mov ecx, dword ptr [ebp+arg1] 88 | xor eax, eax 89 | rep stosb 90 | 91 | ; read console handle 92 | push STD_INPUT_HANDLE 93 | call GetStdHandle 94 | mov dword ptr [ebp+local0], eax 95 | 96 | ; init local vars 97 | mov dword ptr [ebp+local3], 0 ; num char read for separator 98 | lea ebx, dword ptr [ebp+local1] ; lpNumberOfCharsRead 99 | lea esi, dword ptr [ebp+local2] ; read character 100 | mov edi, dword ptr [ebp+arg0] ; pointer to output buffer location to write the char 101 | 102 | @read_char: 103 | ; check if the max number of chars to read is reached 104 | mov eax, edi 105 | sub eax, dword ptr [ebp+arg0] 106 | add eax, 2h 107 | cmp eax, dword ptr [ebp+arg1] 108 | jae @exit 109 | 110 | ; read character 111 | push 0h 112 | push ebx 113 | push 1 114 | push esi 115 | push dword ptr [ebp+local0] 116 | call ReadConsoleA 117 | 118 | ; check newline character 119 | mov al, byte ptr [esi] 120 | cmp al, 0ah 121 | je @exit 122 | cmp al, 0dh 123 | je @exit 124 | 125 | ; store character in output buffer 126 | mov byte ptr [edi], al 127 | inc dword ptr [ebp+local4] 128 | 129 | ; print character to console 130 | push edi 131 | call print_line 132 | 133 | ; move buffer pointer 134 | inc edi 135 | 136 | ; check if must print separator 137 | cmp dword ptr [ebp+arg2], 0h 138 | je @f 139 | 140 | inc dword ptr [ebp+local3] 141 | mov eax, dword ptr [ebp+local3] 142 | cmp eax, dword ptr [ebp+arg3] 143 | jnz @f 144 | 145 | ; print separator 146 | mov dword ptr [ebp+local3], 0h 147 | push dword ptr [ebp+arg2] 148 | call print_line 149 | @@: 150 | jmp @read_char 151 | 152 | @exit: 153 | ; store newline character and print it 154 | mov eax, edi 155 | mov byte ptr [edi], 0dh 156 | inc edi 157 | mov byte ptr [edi], 0ah 158 | push eax 159 | call print_line 160 | 161 | ; return num of chars read 162 | mov eax, dword ptr [ebp+local4] 163 | 164 | mov esp, ebp 165 | pop ebp 166 | ret 167 | read_line endp 168 | 169 | ; 170 | ; Convert input license key to usable format 171 | ; Parameter: input license 172 | ; 173 | normalize_license proc 174 | push ebp 175 | mov ebp, esp 176 | mov esi, dword ptr [ebp+arg0] 177 | 178 | @@: 179 | mov al, byte ptr [esi] 180 | xor ebx, ebx 181 | 182 | ; check for endline 183 | cmp al, 0ah 184 | je @exit 185 | cmp al, 0dh 186 | je @exit 187 | 188 | ; convert from ascii to hex 189 | cmp al, '0' 190 | cmovae bx, word ptr [g_ascii_num] 191 | cmp al, 'A' 192 | cmovae bx, word ptr [g_ascii_upper] 193 | cmp al, 'a' 194 | cmovae bx, word ptr [g_ascii_lower] 195 | sub al, bl 196 | 197 | ; write value and loop 198 | mov byte ptr [esi], al 199 | inc esi 200 | jmp @b 201 | 202 | @exit: 203 | ; set null byte 204 | mov byte ptr [esi], 0h 205 | mov esp, ebp 206 | pop ebp 207 | ret 208 | normalize_license endp 209 | 210 | ; 211 | ; Verifies that the character are in 0-f space 212 | ; Parameter: license, license size 213 | ; Return: 1 if the license is valid, 0 otherwise 214 | ; 215 | check_license_format proc 216 | push ebp 217 | mov ebp, esp 218 | sub esp, sizeof dword 219 | 220 | ; check license size 221 | mov ecx, dword ptr [ebp+arg1] 222 | cmp ecx, 5dh 223 | ja @error 224 | 225 | mov esi, dword ptr [ebp+arg0] 226 | @@: 227 | lodsb 228 | cmp al, 12h 229 | ja @error 230 | loop @b 231 | mov eax, 1 232 | jmp @exit 233 | 234 | @error: 235 | xor eax, eax 236 | jmp @exit 237 | 238 | @exit: 239 | mov esp, ebp 240 | pop ebp 241 | ret 242 | check_license_format endp 243 | 244 | ; 245 | ; Read license from command-line. 246 | ; Parameters: the buffer to store the license, the max number of char to read 247 | ; Return: the license length, or 0 if error 248 | ; 249 | read_lincese proc 250 | push ebp 251 | mov ebp, esp 252 | sub esp, sizeof dword 253 | 254 | ; read license 255 | push 5h 256 | push offset [g_license_separator] 257 | push dword ptr [ebp+arg1] 258 | push dword ptr [ebp+arg0] 259 | call read_line 260 | mov dword ptr [ebp+local0], eax 261 | 262 | ; normalize license 263 | push dword ptr [ebp+arg0] 264 | call normalize_license 265 | 266 | ; check if it is in correct format 267 | push dword ptr [ebp+local0] 268 | push dword ptr [ebp+arg0] 269 | call check_license_format 270 | test eax, eax 271 | jz @exit 272 | mov eax, dword ptr [ebp+local0] 273 | 274 | @exit: 275 | mov esp, ebp 276 | pop ebp 277 | ret 278 | read_lincese endp 279 | 280 | ; 281 | ; Read username from command-line 282 | ; Parameters: the buffer to store the license 283 | ; 284 | read_username proc 285 | push ebp 286 | mov ebp, esp 287 | 288 | ; read username 289 | push 0h 290 | push 0h 291 | push dword ptr [ebp+arg1] 292 | push dword ptr [ebp+arg0] 293 | call read_line 294 | 295 | ; remove newline 296 | mov ecx, -1h 297 | mov edi, dword ptr [ebp+arg0] 298 | mov eax, 0dh 299 | repne scasb 300 | dec edi 301 | mov byte ptr [edi], 0h 302 | 303 | ; check username size 304 | strlen (dword ptr [ebp+arg0]) 305 | cmp ecx, 10h 306 | jae @exit 307 | 308 | ; expand username to fill 16 chars 309 | mov esi, dword ptr [ebp+arg0] 310 | mov edi, esi 311 | add edi, ecx 312 | 313 | @@: 314 | lodsb 315 | mov byte ptr [edi], al 316 | inc edi 317 | loop @b 318 | 319 | ; check the length again 320 | mov esi, dword ptr [ebp+arg0] 321 | strlen esi 322 | cmp ecx, 10h 323 | jb @b 324 | 325 | @exit: 326 | mov esp, ebp 327 | pop ebp 328 | ret 329 | read_username endp 330 | 331 | ; 332 | ; Print a given string in a specified time 333 | ; Parameters: string, string length, time 334 | ; 335 | print_slow proc 336 | push ebp 337 | mov ebp, esp 338 | 339 | ; compute how log I have to wait for each char 340 | xor edx, edx 341 | mov eax, dword ptr [ebp+arg2] 342 | mov ecx, dword ptr [ebp+arg1] 343 | mov ebx, 3e8h 344 | mul ebx 345 | div ecx 346 | mov edi, eax 347 | 348 | ; print the string 349 | mov esi, dword ptr [ebp+arg0] 350 | @@: 351 | push ecx 352 | push 1 353 | push esi 354 | call print_buffer 355 | add esp, 8h 356 | inc esi 357 | push edi 358 | call sleep 359 | pop ecx 360 | loop @b 361 | 362 | mov esp, ebp 363 | pop ebp 364 | ret 365 | print_slow endp -------------------------------------------------------------------------------- /x64Check/x64Check.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {ead64984-a0dc-4384-9d34-c29c61df12e7} 25 | x64Check 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | false 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Level3 89 | true 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | MachineX64 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | true 131 | true 132 | true 133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 134 | true 135 | 136 | 137 | Console 138 | true 139 | true 140 | true 141 | main 142 | 143 | 144 | 145 | 146 | Document 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /Src/s4tanic0d3.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {31256678-83bf-446f-8598-b2b1b398b9ee} 25 | CryptObfuscatorSln 26 | 10.0 27 | s4tanic0d3 28 | 29 | 30 | 31 | Application 32 | true 33 | v142 34 | MultiByte 35 | 36 | 37 | Application 38 | false 39 | v142 40 | true 41 | MultiByte 42 | 43 | 44 | Application 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | true 83 | 84 | 85 | false 86 | 87 | 88 | 89 | Level3 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | true 106 | true 107 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | true 109 | 110 | 111 | Console 112 | true 113 | true 114 | false 115 | false 116 | false 117 | true 118 | 119 | 120 | 121 | 122 | Level3 123 | true 124 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 125 | true 126 | 127 | 128 | Console 129 | true 130 | 131 | 132 | 133 | 134 | Level3 135 | true 136 | true 137 | true 138 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 139 | true 140 | 141 | 142 | Console 143 | true 144 | true 145 | true 146 | 147 | 148 | 149 | 150 | Document 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /Src/utility.inc: -------------------------------------------------------------------------------- 1 | ; return the string length in ECX 2 | strlen macro input 3 | push edi 4 | push eax 5 | mov ecx, 0ffffh 6 | mov edi, input 7 | xor eax, eax 8 | repnz scasb 9 | sub edi, input 10 | dec edi 11 | mov ecx, edi 12 | pop eax 13 | pop edi 14 | endm 15 | 16 | ; 17 | ; Unprotect all program memory 18 | ; 19 | unprotect_code proc 20 | push ebp 21 | mov ebp, esp 22 | 23 | ; get base address 24 | assume fs:nothing 25 | mov eax, dword ptr [fs:30h] 26 | assume fs:error 27 | mov eax, dword ptr [eax+8h] 28 | 29 | ; get size of image 30 | mov ebx, dword ptr [eax+3ch] 31 | add ebx, eax 32 | mov ebx, dword ptr [ebx+50h] 33 | 34 | ; unprotect code in order to be easibly modifiable 35 | ; yes this is extremly inefficient I know :) 36 | sub esp, 4 37 | push esp 38 | push PAGE_EXECUTE_READWRITE 39 | push ebx 40 | push eax 41 | call VirtualProtect 42 | 43 | pop eax 44 | mov esp, ebp 45 | pop ebp 46 | ret 47 | unprotect_code endp 48 | 49 | ; 50 | ; initialize the global vars containing the start and end address of protected code 51 | ; 52 | find_protected_code proc 53 | push ebp 54 | mov ebp, esp 55 | 56 | assume fs:nothing 57 | mov eax, dword ptr [fs:30h] 58 | assume fs:error 59 | mov eax, dword ptr [eax+8h] 60 | push eax 61 | 62 | @@: ; find start 63 | inc eax 64 | mov ebx, dword ptr [eax] 65 | cmp ebx, marker_1 66 | jne @b 67 | add eax, sizeof dword 68 | mov ebx, dword ptr [eax] 69 | cmp ebx, marker_2 70 | jne @b 71 | add eax, sizeof dword 72 | mov ebx, dword ptr [eax] 73 | cmp ebx, marker_3 74 | jne @b 75 | add eax, sizeof dword 76 | mov ebx, dword ptr [eax] 77 | cmp ebx, marker_4 78 | jne @b 79 | add eax, sizeof dword 80 | mov dword ptr [g_saved_start_protected_code], eax 81 | 82 | pop eax 83 | @@: ; find end 84 | inc eax 85 | mov ebx, dword ptr [eax] 86 | cmp ebx, marker_4 87 | jne @b 88 | add eax, sizeof dword 89 | mov ebx, dword ptr [eax] 90 | cmp ebx, marker_3 91 | jne @b 92 | add eax, sizeof dword 93 | mov ebx, dword ptr [eax] 94 | cmp ebx, marker_2 95 | jne @b 96 | add eax, sizeof dword 97 | mov ebx, dword ptr [eax] 98 | cmp ebx, marker_1 99 | jne @b 100 | sub eax, sizeof dword 101 | mov [g_saved_end_protected_code], eax 102 | 103 | mov esp, ebp 104 | pop ebp 105 | ret 106 | find_protected_code endp 107 | 108 | ; 109 | ; Copy memory buffer 110 | ; Parameters: src address, dest addr, size 111 | ; 112 | mem_copy macro src, dest, size 113 | mov esi, src 114 | mov edi, dest 115 | mov ecx, size 116 | rep movsb 117 | endm 118 | 119 | ; 120 | ; RC4 decrypt the input buffer using the input key 121 | ; Input: key, buffer, buffer size 122 | ; 123 | rc4_decrypt proc 124 | push ebp 125 | mov ebp, esp 126 | sub esp, 2 * sizeof dword 127 | 128 | ; make space for S state 129 | sub esp, 0100h 130 | mov dword ptr [ebp+local0], esp 131 | mov esi, esp 132 | 133 | ; set initial S state 134 | mov ecx, 0100h 135 | xor eax, eax 136 | @@: 137 | mov byte ptr [esi], al 138 | inc al 139 | inc esi 140 | loop @b 141 | 142 | ; KSA 143 | mov ecx, 0100h 144 | mov esi, dword ptr [ebp+local0] 145 | mov dword ptr [ebp+local1], 0h 146 | mov edx, dword ptr [ebp+arg0] 147 | @@: 148 | ; add S[i] 149 | lea edi, dword ptr [ecx-0100h] 150 | neg edi 151 | lea edi, dword ptr [esi+edi] 152 | movzx eax, byte ptr [edi] 153 | mov ebx, eax 154 | 155 | ; add key[i % key.Length] and rotate 156 | add bl, dl 157 | ror edx, 8 158 | 159 | ; updated j 160 | add dword ptr [ebp+local1], ebx 161 | and dword ptr [ebp+local1], 0ffh 162 | 163 | ; do swap S[i], S[j] 164 | ; save S[i] 165 | movzx ebx, byte ptr [edi] 166 | push ebx 167 | 168 | ; S[i] = S[j] 169 | mov ebx, dword ptr [ebp+local1] 170 | lea ebx, dword ptr [esi+ebx] 171 | mov al, byte ptr [ebx] 172 | mov byte ptr [edi], al 173 | 174 | ; S[j] = saved S[i] 175 | pop eax 176 | mov byte ptr [ebx], al 177 | 178 | loop @b 179 | 180 | ; PRGA 181 | mov ecx, dword ptr [ebp+arg2] 182 | mov dword ptr [ebp+local0], 0h 183 | mov dword ptr [ebp+local1], 0h 184 | 185 | @@: 186 | ; i = (i + 1) % N 187 | ; j = (j + S[i]) % N 188 | inc dword ptr [ebp+local0] 189 | and dword ptr [ebp+local0], 0ffh 190 | mov eax, dword ptr [ebp+local0] 191 | lea eax, dword ptr [esi + eax] 192 | movzx eax, byte ptr [eax] 193 | add dword ptr [ebp+local1], eax 194 | and dword ptr [ebp+local1], 0ffh 195 | 196 | ; do swap S[i], S[j] 197 | ; save S[i] 198 | mov edi, dword ptr [ebp+local0] 199 | lea edi, dword ptr [esi+edi] 200 | movzx eax, byte ptr [edi] 201 | push eax 202 | 203 | ; S[i] = S[j] 204 | mov ebx, dword ptr [ebp+local1] 205 | lea ebx, dword ptr [esi+ebx] 206 | mov al, byte ptr [ebx] 207 | mov byte ptr [edi], al 208 | 209 | ; S[j] = saved S[i] 210 | pop eax 211 | mov byte ptr [ebx], al 212 | 213 | ; int rnd = S[(S[i] + S[j]) % N] 214 | mov eax, dword ptr [ebp+local0] 215 | lea eax, dword ptr [esi+eax] 216 | movzx eax, byte ptr [eax] 217 | 218 | mov ebx, dword ptr [ebp+local1] 219 | lea ebx, dword ptr [esi+ebx] 220 | mov bl, byte ptr [ebx] 221 | 222 | add al, bl 223 | and eax, 0ffh 224 | lea ebx, dword ptr [esi+eax] 225 | mov bl, byte ptr [ebx] 226 | 227 | ; ciphertext[n] = rnd ^ plaintext[n] 228 | mov eax, dword ptr [ebp+arg1] 229 | xor byte ptr [eax], bl 230 | inc dword ptr [ebp+arg1] 231 | 232 | loop @b 233 | 234 | mov esp, ebp 235 | pop ebp 236 | ret 237 | rc4_decrypt endp 238 | 239 | ; 240 | ; LRESULT CALLBACK IOProc(LPMMIOINFO lpMMIOInfo, UINT uMessage, LPARAM lParam1, LPARAM lParam2) 241 | ; 242 | IOProc proc 243 | push ebp 244 | mov ebp, esp 245 | 246 | ; save non volatile registers, see: https://docs.microsoft.com/en-us/cpp/build/x64-software-conventions?view=vs-2019#register-usage 247 | push esi 248 | push edi 249 | 250 | assume edx:ptr MMIOINFO 251 | mov edx, dword ptr [ebp+arg0] 252 | 253 | ; validity check 254 | mov eax, dword ptr [edx].lDiskOffset 255 | cmp eax, dword ptr [g_sound_size] 256 | jae @default 257 | 258 | ; MMIOM_OPEN 259 | mov eax, dword ptr [ebp+arg1] 260 | cmp eax, 3h 261 | jnz @mmiom_close 262 | mov eax, dword ptr [g_already_opened] 263 | test eax, eax 264 | jnz @ok 265 | mov dword ptr [g_already_opened], 1h 266 | mov dword ptr [edx].lDiskOffset, 0h 267 | jmp @ok 268 | 269 | ; MMIOM_CLOSE 270 | @mmiom_close: 271 | cmp eax, 4h 272 | jnz @mmiom_read 273 | jmp @ok 274 | 275 | ; MMIOM_READ 276 | @mmiom_read: 277 | cmp eax, 0h 278 | jnz @mmiom_seek 279 | mov edi, dword ptr [ebp+arg2] 280 | mov esi, offset [g_sound] 281 | add esi, dword ptr [edx].lDiskOffset 282 | mov ecx, dword ptr [ebp+arg3] 283 | rep movsb 284 | mov eax, dword ptr [ebp+arg3] 285 | add dword ptr [edx].lDiskOffset, eax 286 | jmp @finish 287 | 288 | ; MMIOM_SEEK 289 | @mmiom_seek: 290 | cmp eax, 2h 291 | jnz @default 292 | mov eax, dword ptr [ebp+arg3] 293 | ; SEEK_SET 294 | cmp eax, 0h 295 | jne @f 296 | mov eax, dword ptr [ebp+arg2] 297 | mov dword ptr [edx].lDiskOffset, eax 298 | @@: 299 | mov eax, dword ptr [edx].lDiskOffset 300 | jmp @finish 301 | 302 | @default: 303 | mov eax, -1h 304 | jmp @finish 305 | 306 | @ok: 307 | xor eax, eax 308 | 309 | @finish: 310 | ; restore non volatile registers 311 | pop edi 312 | pop esi 313 | 314 | mov esp, ebp 315 | pop ebp 316 | ret 10h 317 | IOProc endp 318 | 319 | ; 320 | ; Try to play the wave content 321 | ; Returns 1 if the content if played successfully 322 | ; 323 | play_sound proc 324 | push ebp 325 | mov ebp, esp 326 | 327 | ; allocate space for vars and zero out 328 | sub esp, 2 * sizeof dword 329 | xor eax, eax 330 | 331 | sub esp, sizeof MCI_OPEN_PARMS 332 | mov dword ptr [ebp+local0], esp 333 | mov ecx, sizeof MCI_OPEN_PARMS 334 | mov edi, esp 335 | rep stosb 336 | 337 | sub esp, sizeof MCI_PLAY_PARMS 338 | mov dword ptr [ebp+local1], esp 339 | mov ecx, sizeof MCI_PLAY_PARMS 340 | mov edi, esp 341 | rep stosb 342 | 343 | ; Install a custom I/O procedure 344 | push 010010000h ; MMIO_INSTALLPROC | MMIO_GLOBALPROC 345 | push offset IOProc 346 | push 020543453h 347 | call mmioInstallIOProcA 348 | test eax, eax 349 | jz @error 350 | 351 | ; open WAV device 352 | assume esi:ptr MCI_OPEN_PARMS 353 | mov esi, dword ptr [ebp+local0] 354 | mov dword ptr [esi].lpstrDeviceType, 020ah ; MCI_DEVTYPE_WAVEFORM_AUDIO 355 | mov ebx, offset [g_element_name] 356 | mov dword ptr [esi].lpstrElementName, ebx 357 | 358 | push dword ptr [ebp+local0] 359 | push 03200h ; MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT | MCI_OPEN_TYPE_ID 360 | push 803h ; MCI_OPEN 361 | push 0 362 | call mciSendCommandA 363 | test eax, eax 364 | jnz @error 365 | 366 | ; save device ID 367 | mov eax, dword ptr [esi].wDeviceID 368 | mov dword ptr [g_device_id], eax 369 | 370 | ; play content 371 | lea eax, dword ptr [ebp+local1] 372 | push eax 373 | push 1h ; MCI_NOTIFY 374 | push 0806h ; MCI_PLAY 375 | push dword ptr [esi].wDeviceID 376 | call mciSendCommandA 377 | test eax, eax 378 | jnz @error 379 | 380 | mov eax, 1h 381 | jmp @finish 382 | @error: 383 | xor eax, eax 384 | 385 | @finish: 386 | mov esp, ebp 387 | pop ebp 388 | ret 389 | play_sound endp 390 | 391 | ; 392 | ; Stop the music 393 | ; 394 | stop_sound proc 395 | push ebp 396 | mov ebp, esp 397 | 398 | ; mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL); 399 | push 0h 400 | push 0h 401 | push 804h ; MCI_CLOSE 402 | push dword ptr [g_device_id] 403 | call mciSendCommandA 404 | 405 | mov esp, ebp 406 | pop ebp 407 | ret 408 | stop_sound endp -------------------------------------------------------------------------------- /Src/main.asm: -------------------------------------------------------------------------------- 1 | comment ! 2 | 3 | -=[ s4tanic0d3 ]=- 4 | 5 | After more than 10 years I decided to create another crackme, the third one. Enjoy :) 6 | 7 | You can find my previous crackme at: 8 | - http://crackmes.cf/users/s4tan/crackme1_s4tan/ (2009) 9 | - http://crackmes.cf/users/s4tan/s4tanic0de/ (2009) 10 | 11 | 2020 (C) Antonio 's4tan' Parata 12 | ! 13 | 14 | .686 15 | .model flat, stdcall 16 | .stack 4096 17 | .xmm 18 | 19 | .data 20 | 21 | ; specify if the program must be traced 22 | g_is_trace_enabled dword 0h 23 | 24 | ; bytes containing the content that is encrypted and temporary decrypted for execution 25 | g_saved_encrypted_code_address dword 0h 26 | g_saved_encrypted_code byte 0Fh dup(0h) 27 | g_restore_address dword 0h 28 | 29 | ; constants used to mark the encrypted code 30 | g_saved_start_protected_code dword 0h 31 | g_saved_end_protected_code dword 0h 32 | 33 | ; console strings 34 | g_insert_license db "Please enter your license key: ", 0h 35 | g_insert_username db "Please enter your ID: ", 0h 36 | g_wrong_result db "The inserted license is not valid!", 0h 37 | g_wait db "License validation in process...", 0ah, 0dh, 0h 38 | g_license_separator db "-", 0h 39 | 40 | g_ascii_num word 030h 41 | g_ascii_upper word 037h 42 | g_ascii_lower word 057h 43 | 44 | ; rubik cube vars 45 | g_cube_color db "ywobrg" 46 | g_cube_moves dword 0h 47 | g_cube_moves_length dword 0h 48 | g_verification_magic dword 0b554a050h 49 | 50 | ; play wave vars 51 | g_element_name db 's4tanic0d3.S4T+',0h 52 | g_already_opened dword 0h 53 | g_device_id dword 0h 54 | 55 | include 56 | 57 | .code 58 | 59 | include 60 | include 61 | include 62 | include 63 | includelib 64 | 65 | ; start protected code. The code running under this mode, cannot read "code" or "data" 66 | ; from addresses that are in the encrypted space. 67 | start_protected_code_marker 68 | include 69 | include 70 | end_protected_code_marker 71 | 72 | @function_table: 73 | dword offset compute_initialization_key 74 | dword offset gen_cube_random 75 | dword offset shuffle_cube 76 | dword offset verify_cube_result 77 | dword offset move_F 78 | dword offset move_F_prime 79 | dword offset move_R 80 | dword offset move_R_prime 81 | dword offset move_U 82 | dword offset move_U_prime 83 | dword offset move_L 84 | dword offset move_L_prime 85 | dword offset move_D 86 | dword offset move_D_prime 87 | dword offset move_B 88 | dword offset move_B_prime 89 | dword offset move_S 90 | dword offset move_S_prime 91 | dword offset move_M 92 | dword offset move_M_prime 93 | dword offset move_E 94 | dword offset move_E_prime 95 | 96 | ; 97 | ; restore bytes previously overwritten by decrypted code 98 | ; 99 | restore_bytes proc 100 | push ebp 101 | mov ebp, esp 102 | 103 | mov edi, dword ptr [g_saved_encrypted_code_address] 104 | test edi, edi 105 | jz @exit 106 | 107 | ; restore bytes temporarly decrypted 108 | mem_copy offset g_saved_encrypted_code, dword ptr [g_saved_encrypted_code_address], sizeof g_saved_encrypted_code 109 | mov dword ptr [g_saved_encrypted_code_address], 0h 110 | 111 | @exit: 112 | mov esp, ebp 113 | pop ebp 114 | ret 115 | restore_bytes endp 116 | 117 | ; 118 | ; handle the trap exception 119 | ; Parameter: CONTEXT 120 | ; 121 | trap_handler proc 122 | push ebp 123 | mov ebp, esp 124 | 125 | ; obtains the instruction address causing the fault 126 | assume ebx: ptr CONTEXT 127 | mov ebx, [ebp+arg0] 128 | mov eax, [ebx].rEip 129 | 130 | ; verify that the faulty EIP is inside the protected range, if not does not decrypt 131 | cmp eax, dword ptr [g_saved_start_protected_code] 132 | jb @exit 133 | cmp eax, dword ptr [g_saved_end_protected_code] 134 | ja @exit 135 | 136 | ; decrypt the code that must be executed 137 | push eax 138 | call decrypt_code 139 | 140 | @exit: 141 | mov esp, ebp 142 | pop ebp 143 | ret 144 | trap_handler endp 145 | 146 | ; 147 | ; call a specific function that was invoked via obfuscation 148 | ; Parameter: CONTEXT 149 | ; 150 | call_nano_handler proc 151 | push ebp 152 | mov ebp, esp 153 | 154 | mov esi, [ebp+arg0] 155 | assume esi: ptr CONTEXT 156 | 157 | ; adjust stack 158 | mov ebx, [esi].rEsp 159 | sub ebx, sizeof dword 160 | mov dword ptr [esi].rEsp, ebx 161 | 162 | ; get function 163 | mov eax, [esi].rEip 164 | inc eax 165 | movzx eax, byte ptr [eax] 166 | lea eax, dword ptr [@function_table + eax * sizeof dword] 167 | mov edx, dword ptr [eax] 168 | 169 | ; set return address 170 | mov eax, [esi].rEip 171 | add eax, 2 172 | mov dword ptr [ebx], eax 173 | 174 | ; set new EIP 175 | mov [esi].rEip, edx 176 | 177 | xor eax, eax 178 | mov esp, ebp 179 | pop ebp 180 | ret 181 | call_nano_handler endp 182 | 183 | ; 184 | ; See https://docs.microsoft.com/en-us/windows/win32/devnotes/--c-specific-handler2 185 | ; 186 | exception_handler proc 187 | push ebp 188 | mov ebp, esp 189 | 190 | ; verify if it is a nano call 191 | mov ebx, [ebp+arg0] 192 | cmp dword ptr [ebx], EXCEPTION_PRIVILEGED_INSTRUCTION 193 | jne @f 194 | push [ebp+arg2] 195 | call call_nano_handler 196 | 197 | ; replace previous instructions if necessary 198 | call restore_bytes 199 | 200 | ; invoke trap handler 201 | push [ebp+arg2] 202 | call trap_handler 203 | xor eax, eax 204 | jmp @set_trap_flag 205 | 206 | @@: 207 | ; verify that the exception is due to single step 208 | cmp dword ptr [ebx], EXCEPTION_SINGLE_STEP 209 | jne @not_handled 210 | 211 | ; replace previous instructions if necessary 212 | call restore_bytes 213 | 214 | ; invoke trap handler 215 | push [ebp+arg2] 216 | call trap_handler 217 | xor eax, eax 218 | jmp @set_trap_flag 219 | 220 | @not_handled: 221 | mov eax, 1 222 | mov dword ptr [g_is_trace_enabled], 0h 223 | jmp @exit 224 | 225 | @set_trap_flag: 226 | ; check if single step is enabled 227 | cmp dword ptr [g_is_trace_enabled], 0h 228 | jz @exit 229 | 230 | ; set trap flag in CONTEXT again 231 | mov ebx, [ebp+arg2] 232 | assume ebx: ptr CONTEXT 233 | or dword ptr [ebx].EFlags, 100h 234 | 235 | @exit: 236 | mov esp, ebp 237 | pop ebp 238 | ret 239 | exception_handler endp 240 | 241 | ; 242 | ; Verify is a debugger is attached and if so modify then number to 243 | ; initialize the cube 244 | ; 245 | check_debugger proc 246 | push ebp 247 | mov ebp, esp 248 | 249 | ; load to ESI the value 250 | mov esi, dword ptr [g_verification_magic] 251 | 252 | ; transit to 64-bit world 253 | push 33h 254 | call $+5 255 | add dword ptr [esp], 5h 256 | retf 257 | 258 | ; check debugger and return to 32-bit 259 | db 065h, 048h, 08bh, 004h, 025h, 030h, 000h, 000h, 000h 260 | db 048h, 08bh, 040h, 060h 261 | db 048h, 00fh, 0b6h, 040h, 002h 262 | db 048h, 085h, 0c0h 263 | db 048h, 0bbh, 0deh, 0c0h, 0adh, 0bah, 000h, 000h, 000h, 000h 264 | db 048h, 0b8h, 0beh, 0bah, 0feh, 0cah, 000h, 000h, 000h, 000h 265 | db 048h, 00fh, 044h, 0d8h 266 | db 048h, 033h, 0f3h 267 | db 0e8h, 000h, 000h, 000h, 000h 268 | db 0c7h, 044h, 024h, 004h, 023h, 000h, 000h, 000h 269 | db 083h, 004h, 024h, 00dh 270 | db 0cbh 271 | 272 | ; save back the result, the correct value should be 7faa1aeeh 273 | mov dword ptr [g_verification_magic], esi 274 | 275 | mov esp, ebp 276 | pop ebp 277 | ret 278 | check_debugger endp 279 | 280 | main proc 281 | push ebp 282 | mov ebp, esp 283 | 284 | max_input_length equ 60h 285 | sub esp, sizeof dword * 2 286 | 287 | ; make space for username and license 288 | sub esp, max_input_length 289 | mov dword ptr [ebp+local0], esp 290 | 291 | sub esp, max_input_length 292 | mov dword ptr [ebp+local1], esp 293 | 294 | ; initialize console 295 | call init_console 296 | 297 | ; print username 298 | push offset [g_insert_username] 299 | call print_line 300 | 301 | ; read username 302 | push max_input_length 303 | sub dword ptr [esp], 1 304 | push dword ptr [ebp+local0] 305 | call read_username 306 | 307 | ; print license key 308 | push offset [g_insert_license] 309 | call print_line 310 | 311 | ; read license key 312 | push max_input_length 313 | sub dword ptr [esp], 1 314 | push dword ptr [ebp+local1] 315 | call read_lincese 316 | test eax, eax 317 | jz @license_not_valid 318 | mov dword ptr [g_cube_moves_length], eax 319 | 320 | ; unprotect all program memory 321 | call unprotect_code 322 | 323 | ; fill global vars with start and end addresses of protected code 324 | call find_protected_code 325 | 326 | ; print wait message 327 | push offset [g_wait] 328 | call print_line 329 | 330 | ; check debugger 331 | call check_debugger 332 | 333 | ; set the exception handler 334 | push offset exception_handler 335 | assume fs:nothing 336 | push dword ptr [fs:0] 337 | mov [fs:0], esp 338 | assume fs:error 339 | 340 | ; enable trap flag and execute obfuscated code that is inside marks 341 | mov dword ptr [g_is_trace_enabled], 1h 342 | pushfd 343 | or word ptr [esp], 100h 344 | popfd 345 | 346 | ; check the username/license values 347 | push dword ptr [ebp+local1] 348 | push dword ptr [ebp+local0] 349 | call check_input 350 | 351 | ; disable tracing 352 | mov dword ptr [g_is_trace_enabled], 0h 353 | 354 | ; save key 355 | push eax 356 | 357 | ; use the result to decrypt the data 358 | push dword ptr [g_sound_size] 359 | push offset [g_sound] 360 | push eax 361 | call rc4_decrypt 362 | add esp, 0ch 363 | 364 | ; play the sound 365 | call play_sound 366 | test eax, eax 367 | jz @license_not_valid 368 | 369 | ; decrypt congratz 370 | pop eax 371 | push dword ptr [g_success_size] 372 | push offset [g_success] 373 | push eax 374 | call rc4_decrypt 375 | 376 | ; print the congratz text 377 | push 1fh 378 | push dword ptr [g_success_size] 379 | push offset [g_success] 380 | call print_slow 381 | 382 | push 7d0h 383 | call sleep 384 | 385 | ; stop the sound 386 | call stop_sound 387 | xor eax, eax 388 | jmp @exit 389 | 390 | @license_not_valid: 391 | push offset [g_wrong_result] 392 | call print_line 393 | mov eax, 1h 394 | jmp @exit 395 | 396 | @exit: 397 | push eax 398 | call ExitProcess 399 | 400 | mov esp, ebp 401 | pop ebp 402 | ret 403 | main endp 404 | end main -------------------------------------------------------------------------------- /Src/obfuscation.inc: -------------------------------------------------------------------------------- 1 | g_random_multiplier dword 010101h 2 | g_random_adder dword 415927h 3 | 4 | ; The following code implements what described in: 5 | ; - https://www.msreverseengineering.com/blog/2015/6/29/transparent-deobfuscation-with-ida-processor-module-extensions 6 | ; This protection is very similar to nanomites protection. See http://deroko.phearless.org/nanomites.zip 7 | ; file nanomites.asm line 1741 8 | 9 | n_compute_initialization_key equ 0h 10 | n_gen_cube_random equ 1h 11 | n_shuffle_cube equ 2h 12 | n_verify_cube_result equ 3h 13 | n_move_F equ 4h 14 | n_move_F_prime equ 5h 15 | n_move_R equ 6h 16 | n_move_R_prime equ 7h 17 | n_move_U equ 8h 18 | n_move_U_prime equ 9h 19 | n_move_L equ 0Ah 20 | n_move_L_prime equ 0Bh 21 | n_move_D equ 0Ch 22 | n_move_D_prime equ 0Dh 23 | n_move_B equ 0Eh 24 | n_move_B_prime equ 0Fh 25 | n_move_S equ 10h 26 | n_move_S_prime equ 11h 27 | n_move_M equ 12h 28 | n_move_M_prime equ 13h 29 | n_move_E equ 14h 30 | n_move_E_prime equ 15h 31 | 32 | nano_call macro func_index 33 | in al, func_index 34 | endm 35 | 36 | ; 37 | ; generate a random number used to deobfuscate 38 | ; Parameters: address of the instruction to deobfuscate 39 | ; 40 | gen_random proc 41 | push ebp 42 | mov ebp, esp 43 | 44 | movzx eax, byte ptr [ebp+arg0] 45 | mov edx, dword ptr [g_random_multiplier] 46 | mul edx 47 | add eax, dword ptr [g_random_adder] 48 | 49 | popcnt ecx, eax 50 | test byte ptr [ebp+arg0], 1h 51 | jz @f 52 | ror al, cl 53 | jmp @exit 54 | @@: 55 | rol al, cl 56 | 57 | @exit: 58 | and eax, 0ffh 59 | mov ecx, 0ah 60 | xor edx, edx 61 | div ecx 62 | mov eax, edx 63 | 64 | mov esp, ebp 65 | pop ebp 66 | ret 67 | gen_random endp 68 | 69 | ; 70 | ; This function read the given entry in the array, set the "used" bit and update the array 71 | ; Parameter: the index of the routine to read 72 | ; 73 | get_routine_entry proc 74 | push ebp 75 | mov ebp, esp 76 | 77 | mov eax, dword ptr [ebp+arg0] 78 | mov esi, offset g_deobfuscation_routines 79 | lea edx, [esi + eax * sizeof dword] 80 | mov eax, dword ptr [edx] 81 | cmp eax, 0h 82 | je @exit 83 | 84 | ; set entry and return result 85 | bts eax, 0ffffffffh 86 | mov dword ptr [edx], eax 87 | 88 | @exit: 89 | mov esp, ebp 90 | pop ebp 91 | ret 92 | get_routine_entry endp 93 | 94 | ; 95 | ; Get the deobfuscation routine according to the given address 96 | ; Parameter: the address to deobfuscate 97 | ; 98 | get_routine proc 99 | push ebp 100 | mov ebp, esp 101 | sub esp, 2 * sizeof dword 102 | 103 | ; generate and save random 104 | push dword ptr [ebp+arg0] 105 | call gen_random 106 | mov dword ptr [ebp+local1], eax 107 | add esp, 4 108 | 109 | ; update status 110 | ; choose deobfuscation routine. If the first bit is not set the function 111 | ; can be invoked. The bit is then set to 1 to ignore it the next time. 112 | mov ecx, num_deobfuscation_routines 113 | mov esi, offset g_deobfuscation_routines 114 | lea edx, [esi + eax * sizeof dword] 115 | 116 | @@: 117 | mov eax, dword ptr [edx] 118 | cmp eax, 0h 119 | 120 | ; round index if necessary 121 | cmove edx, esi 122 | cmove eax, dword ptr [edx] 123 | 124 | bts eax, 0ffffffffh 125 | mov dword ptr [edx], eax 126 | jnc @routine_found 127 | add edx, sizeof dword 128 | loop @B 129 | 130 | ; not routine available found, all array was traversed, need to re-initialize the array 131 | push dword ptr [g_saved_start_protected_code] 132 | call init_routine_array 133 | mov ecx, num_deobfuscation_routines 134 | mov eax, dword ptr [ebp+local1] 135 | lea edx, [esi + eax * sizeof dword] 136 | jmp @B 137 | 138 | @routine_found: 139 | ; clean the result and return the routine address 140 | and eax, 7fffffffh 141 | 142 | mov esp, ebp 143 | pop ebp 144 | ret 145 | get_routine endp 146 | 147 | ; 148 | ; Initialize the array containing the routines to deobfuscate 149 | ; Parameter the address that will be deobfuscated next 150 | ; 151 | init_routine_array proc 152 | push ebp 153 | mov ebp, esp 154 | sub esp, 4 * sizeof dword 155 | 156 | ; save non volatile registers 157 | mov dword ptr [ebp+local2], esi 158 | mov dword ptr [ebp+local3], edi 159 | 160 | ; init array deobfuscation routines 161 | mov edi, offset g_deobfuscation_routines 162 | mov esi, offset @deobfuscation_routines 163 | mov ecx, num_deobfuscation_routines 164 | rep movsd 165 | mov dword ptr [edi], 0h 166 | 167 | ; according to the input address must set the given routine as not available. 168 | ; Start by computing the base address 169 | mov eax, dword ptr [ebp+arg0] 170 | sub eax, dword ptr [g_saved_start_protected_code] 171 | xor edx, edx 172 | mov ebx, num_deobfuscation_routines 173 | div ebx 174 | 175 | ; check if there are routines to set 176 | cmp edx, 0h 177 | je @exit 178 | 179 | ; save reminder 180 | mov ecx, edx 181 | 182 | ; compute base address 183 | xor edx, edx 184 | mov ebx, num_deobfuscation_routines 185 | mul ebx 186 | add eax, dword ptr [g_saved_start_protected_code] 187 | mov dword ptr [ebp+local0], eax 188 | 189 | ; set all routines to invoked 190 | @@: 191 | mov dword ptr [ebp+local1], ecx 192 | push dword ptr [ebp+local0] 193 | call get_routine 194 | inc dword ptr [ebp+local0] 195 | mov ecx, dword ptr [ebp+local1] 196 | loop @B 197 | 198 | jmp @exit 199 | 200 | @deobfuscation_routines: 201 | dword offset deobfuscation0 202 | dword offset deobfuscation1 203 | dword offset deobfuscation2 204 | dword offset deobfuscation3 205 | dword offset deobfuscation4 206 | dword offset deobfuscation5 207 | dword offset deobfuscation6 208 | dword offset deobfuscation7 209 | dword offset deobfuscation8 210 | dword offset deobfuscation9 211 | num_deobfuscation_routines equ ($ - @deobfuscation_routines) / sizeof dword 212 | 213 | @exit: 214 | ; restore registers 215 | mov esi, dword ptr [ebp+local2] 216 | mov edi, dword ptr [ebp+local3] 217 | 218 | mov esp, ebp 219 | pop ebp 220 | ret 221 | init_routine_array endp 222 | 223 | ; 224 | ; deobfuscate the byte at the given address 225 | ; Parameters: address of the byte to deobfuscate 226 | ; 227 | deobfuscate proc 228 | push ebp 229 | mov ebp, esp 230 | sub esp, 3 * sizeof dword 231 | 232 | ; save not volatile registers 233 | mov dword ptr [ebp+local0], esi 234 | mov dword ptr [ebp+local1], edi 235 | 236 | ; obtain the routine to invoke for the deobfuscation 237 | push dword ptr [ebp+arg0] 238 | call get_routine 239 | 240 | ; call the routine 241 | push dword ptr [ebp+arg0] 242 | call eax 243 | 244 | ; restore registers 245 | mov esi, dword ptr [ebp+local0] 246 | mov edi, dword ptr [ebp+local1] 247 | 248 | mov esp, ebp 249 | pop ebp 250 | ret 251 | deobfuscate endp 252 | 253 | ; 254 | ; Decrypt the instruction that must be executed 255 | ; Parameters: Address of the instruction to decrypt 256 | ; 257 | decrypt_code proc 258 | push ebp 259 | mov ebp, esp 260 | sub esp, sizeof dword 261 | 262 | ; save encrypted bytes in buffer and initialize routines 263 | mem_copy dword ptr [ebp+arg0], offset g_saved_encrypted_code, sizeof g_saved_encrypted_code 264 | 265 | ; initialize the routines status 266 | push dword ptr [ebp+arg0] 267 | call init_routine_array 268 | 269 | ; deobfuscate the code 270 | mov ecx, sizeof g_saved_encrypted_code 271 | mov esi, dword ptr [ebp+arg0] 272 | mov dword ptr [g_saved_encrypted_code_address], esi 273 | 274 | @@: 275 | push ecx 276 | push esi 277 | call deobfuscate 278 | mov byte ptr [esi], al 279 | inc esi 280 | add esp, 4 281 | pop ecx 282 | loop @B 283 | 284 | mov esp, ebp 285 | pop ebp 286 | ret 287 | decrypt_code endp 288 | 289 | ; 290 | ; All deobfuscation routines take as parameter: address 291 | ; 292 | deobfuscation0 proc 293 | push ebp 294 | mov ebp, esp 295 | 296 | mov eax, dword ptr [ebp+arg0] 297 | movzx eax, byte ptr [eax] 298 | xor eax, 0cch 299 | 300 | mov esp, ebp 301 | pop ebp 302 | ret 303 | deobfuscation0 endp 304 | 305 | deobfuscation1 proc 306 | push ebp 307 | mov ebp, esp 308 | 309 | mov eax, dword ptr [ebp+arg0] 310 | movzx eax, byte ptr [eax] 311 | sub eax, 0aah 312 | and eax, 0ffh 313 | 314 | mov esp, ebp 315 | pop ebp 316 | ret 317 | deobfuscation1 endp 318 | 319 | deobfuscation2 proc 320 | push ebp 321 | mov ebp, esp 322 | 323 | mov eax, dword ptr [ebp+arg0] 324 | movzx eax, byte ptr [eax] 325 | ror al, 2 326 | add eax, 042h 327 | and eax, 0ffh 328 | 329 | mov esp, ebp 330 | pop ebp 331 | ret 332 | deobfuscation2 endp 333 | 334 | deobfuscation3 proc 335 | push ebp 336 | mov ebp, esp 337 | 338 | mov eax, dword ptr [ebp+arg0] 339 | movzx eax, byte ptr [eax] 340 | 341 | mov ebx, dword ptr [ebp+arg0] 342 | xor eax, ebx 343 | and eax, 0ffh 344 | 345 | mov esp, ebp 346 | pop ebp 347 | ret 348 | deobfuscation3 endp 349 | 350 | deobfuscation4 proc 351 | push ebp 352 | mov ebp, esp 353 | 354 | mov eax, dword ptr [ebp+arg0] 355 | movzx eax, byte ptr [eax] 356 | 357 | mov ebx, dword ptr [ebp+arg0] 358 | sub eax, ebx 359 | and eax, 0ffh 360 | 361 | mov esp, ebp 362 | pop ebp 363 | ret 364 | deobfuscation4 endp 365 | 366 | deobfuscation5 proc 367 | push ebp 368 | mov ebp, esp 369 | 370 | mov eax, dword ptr [ebp+arg0] 371 | movzx eax, byte ptr [eax] 372 | 373 | mov ebx, dword ptr [ebp+arg0] 374 | add eax, ebx 375 | and eax, 0ffh 376 | 377 | mov esp, ebp 378 | pop ebp 379 | ret 380 | deobfuscation5 endp 381 | 382 | deobfuscation6 proc 383 | push ebp 384 | mov ebp, esp 385 | 386 | mov eax, dword ptr [ebp+arg0] 387 | movzx eax, byte ptr [eax] 388 | rol al, 4 389 | not eax 390 | and eax, 0ffh 391 | 392 | mov esp, ebp 393 | pop ebp 394 | ret 395 | deobfuscation6 endp 396 | 397 | deobfuscation7 proc 398 | push ebp 399 | mov ebp, esp 400 | 401 | mov eax, dword ptr [ebp+arg0] 402 | movzx eax, byte ptr [eax] 403 | not eax 404 | xor eax, 17h 405 | and eax, 0ffh 406 | 407 | mov esp, ebp 408 | pop ebp 409 | ret 410 | deobfuscation7 endp 411 | 412 | deobfuscation8 proc 413 | push ebp 414 | mov ebp, esp 415 | 416 | mov eax, dword ptr [ebp+arg0] 417 | movzx eax, byte ptr [eax] 418 | not eax 419 | 420 | mov ebx, dword ptr [ebp+arg0] 421 | not ebx 422 | 423 | xor eax, ebx 424 | and eax, 0ffh 425 | 426 | mov esp, ebp 427 | pop ebp 428 | ret 429 | deobfuscation8 endp 430 | 431 | deobfuscation9 proc 432 | push ebp 433 | mov ebp, esp 434 | 435 | mov eax, dword ptr [ebp+arg0] 436 | movzx eax, byte ptr [eax] 437 | ror al, 3 438 | 439 | mov ebx, dword ptr [ebp+arg0] 440 | rol bl, 6 441 | not ebx 442 | 443 | xor eax, ebx 444 | and eax, 0ffh 445 | 446 | mov esp, ebp 447 | pop ebp 448 | ret 449 | deobfuscation9 endp 450 | 451 | g_deobfuscation_routines dword num_deobfuscation_routines+1 dup(0h) -------------------------------------------------------------------------------- /Src/rubik_cube.inc: -------------------------------------------------------------------------------- 1 | position_1 equ 0h 2 | position_2 equ 8h 3 | position_3 equ 10h 4 | position_4 equ 18h 5 | 6 | ; 7 | ; read the byte from the register at the specified position 8 | ; 9 | read_value_address macro register, position 10 | push register 11 | shr register, position 12 | and register, 0ffh 13 | mov eax, esi 14 | add eax, register 15 | pop register 16 | endm 17 | 18 | ; 19 | ; read value at position1 from reg1 and save it to position2 from reg2 20 | ; Parameters: ESI contains cube buffer 21 | ; 22 | move_value macro reg1, position1, reg2, position2 23 | ; save values 24 | push eax 25 | push edi 26 | 27 | ; read value to move 28 | read_value_address reg1, position1 29 | movzx edi, byte ptr [eax] 30 | 31 | ; read destination address 32 | read_value_address reg2, position2 33 | 34 | ; move value 35 | xchg eax, edi 36 | mov byte ptr [edi], al 37 | 38 | ; restore values 39 | pop eax 40 | pop edi 41 | endm 42 | 43 | ; 44 | ; Move the given cube faces 45 | ; Input: 46 | ; EAX: tmp value 47 | ; EDI: tmp value 48 | ; ESI: cube address 49 | ; EBX: A1|A2|A3|B1 50 | ; ECX: B2|B3|C1|C2 51 | ; EDX: C3|D1|D2|D3 52 | ; 53 | ; after move 54 | ; 55 | ; EBX: D1|D2|D3|A1 56 | ; ECX: A2|A3|B1|B2 57 | ; EDX: B3|C1|C2|C3 58 | shift_right_faces macro 59 | ; save D3,D2,D1 values 60 | read_value_address edx, position_1 61 | movzx eax, byte ptr [eax] 62 | push eax 63 | read_value_address edx, position_2 64 | movzx eax, byte ptr [eax] 65 | push eax 66 | read_value_address edx, position_3 67 | movzx eax, byte ptr [eax] 68 | push eax 69 | 70 | ; move C1,C2,C3 -> D1,D2,D3 71 | move_value ecx, position_2, edx, position_3 72 | move_value ecx, position_1, edx, position_2 73 | move_value edx, position_4, edx, position_1 74 | 75 | ; move B1,B2,B3 -> C1,C2,C3 76 | move_value ebx, position_1, ecx, position_2 77 | move_value ecx, position_4, ecx, position_1 78 | move_value ecx, position_3, edx, position_4 79 | 80 | ; move A1,A2,A3 -> B1,B2,B3 81 | move_value ebx, position_4, ebx, position_1 82 | move_value ebx, position_3, ecx, position_4 83 | move_value ebx, position_2, ecx, position_3 84 | 85 | ; D1 (saved) -> A1 86 | read_value_address ebx, position_4 87 | pop edi 88 | xchg eax, edi 89 | mov byte ptr [edi], al 90 | 91 | ; D2 (saved) -> A2 92 | read_value_address ebx, position_3 93 | pop edi 94 | xchg eax, edi 95 | mov byte ptr [edi], al 96 | 97 | ; D3 (saved) -> A3 98 | read_value_address ebx, position_2 99 | pop edi 100 | xchg eax, edi 101 | mov byte ptr [edi], al 102 | endm 103 | 104 | ; 105 | ; Move the given cube faces 106 | ; Input: 107 | ; EAX: tmp value 108 | ; EDI: tmp value 109 | ; ESI: cube address 110 | ; EBX: A1|A2|A3|B1 111 | ; ECX: B2|B3|C1|C2 112 | ; EDX: C3|D1|D2|D3 113 | ; 114 | ; after move 115 | ; 116 | ; EBX: B1|B2|B3|C1 117 | ; ECX: C2|C3|D1|D2 118 | ; EDX: D3|A1|A2|A3 119 | shift_left_faces macro 120 | ; save A3,A2,A1 values 121 | read_value_address ebx, position_2 122 | movzx eax, byte ptr [eax] 123 | push eax 124 | read_value_address ebx, position_3 125 | movzx eax, byte ptr [eax] 126 | push eax 127 | read_value_address ebx, position_4 128 | movzx eax, byte ptr [eax] 129 | push eax 130 | 131 | ; move B -> A 132 | move_value ebx, position_1, ebx, position_4 133 | move_value ecx, position_4, ebx, position_3 134 | move_value ecx, position_3, ebx, position_2 135 | 136 | ; move C -> B 137 | move_value ecx, position_2, ebx, position_1 138 | move_value ecx, position_1, ecx, position_4 139 | move_value edx, position_4, ecx, position_3 140 | 141 | ; move D -> C 142 | move_value edx, position_3, ecx, position_2 143 | move_value edx, position_2, ecx, position_1 144 | move_value edx, position_1, edx, position_4 145 | 146 | ; A1 (saved) -> D1 147 | read_value_address edx, position_3 148 | pop edi 149 | xchg eax, edi 150 | mov byte ptr [edi], al 151 | 152 | ; A2 (saved) -> D2 153 | read_value_address edx, position_2 154 | pop edi 155 | xchg eax, edi 156 | mov byte ptr [edi], al 157 | 158 | ; A3 (saved) -> D3 159 | read_value_address edx, position_1 160 | pop edi 161 | xchg eax, edi 162 | mov byte ptr [edi], al 163 | endm 164 | 165 | ; 166 | ; Move the given cube faces 167 | ; Input: 168 | ; EAX: tmp value 169 | ; EDI: tmp value 170 | ; ESI: cube address 171 | ; EBX: A1|A2|A3|B1 172 | ; ECX: B2|B3|C1|C2 173 | ; EDX: C3|XX|XX|XX 174 | ; 175 | ; after move 176 | ; 177 | ; EBX: C1|B1|A1|C2 178 | ; ECX: B2|A2|C3|B3 179 | ; EDX: A3|XX|XX|XX 180 | rotate_clockwise_faces macro 181 | ; save B3,C3,A3 values 182 | read_value_address ecx, position_3 183 | movzx eax, byte ptr [eax] 184 | push eax 185 | read_value_address edx, position_4 186 | movzx eax, byte ptr [eax] 187 | push eax 188 | read_value_address ebx, position_2 189 | movzx eax, byte ptr [eax] 190 | push eax 191 | 192 | ; A1 -> A3 193 | move_value ebx, position_4, ebx, position_2 194 | 195 | ; A2 -> B3 196 | move_value ebx, position_3, ecx, position_3 197 | 198 | ; A3 (saved) -> C3 199 | read_value_address edx, position_4 200 | pop edi 201 | xchg eax, edi 202 | mov byte ptr [edi], al 203 | 204 | ; C1 -> A1 205 | move_value ecx, position_2, ebx, position_4 206 | 207 | ; B1 -> A2 208 | move_value ebx, position_1, ebx, position_3 209 | 210 | ; C3 (saved) -> C1 211 | read_value_address ecx, position_2 212 | pop edi 213 | xchg eax, edi 214 | mov byte ptr [edi], al 215 | 216 | ; C2 -> B1 217 | move_value ecx, position_1, ebx, position_1 218 | 219 | ; B3 (saved) -> C2 220 | read_value_address ecx, position_1 221 | pop edi 222 | xchg eax, edi 223 | mov byte ptr [edi], al 224 | endm 225 | 226 | ; 227 | ; Move the given cube faces 228 | ; Input: 229 | ; EAX: tmp value 230 | ; EDI: tmp value 231 | ; ESI: cube address 232 | ; EBX: A1|A2|A3|B1 233 | ; ECX: B2|B3|C1|C2 234 | ; EDX: C3|XX|XX|XX 235 | ; 236 | ; after move 237 | ; 238 | ; EBX: A3|B3|C3|A2 239 | ; ECX: B2|C2|A1|B1 240 | ; EDX: C1|XX|XX|XX 241 | rotate_counterclockwise_faces macro 242 | ; save C2,C3,C1 values 243 | read_value_address ecx, position_1 244 | movzx eax, byte ptr [eax] 245 | push eax 246 | read_value_address edx, position_4 247 | movzx eax, byte ptr [eax] 248 | push eax 249 | read_value_address ecx, position_2 250 | movzx eax, byte ptr [eax] 251 | push eax 252 | 253 | ; A1 -> C1 254 | move_value ebx, position_4, ecx, position_2 255 | 256 | ; B1 -> C2 257 | move_value ebx, position_1, ecx, position_1 258 | 259 | ; C1 (saved) -> C3 260 | read_value_address edx, position_4 261 | pop edi 262 | xchg eax, edi 263 | mov byte ptr [edi], al 264 | 265 | ; A3 -> A1 266 | move_value ebx, position_2, ebx, position_4 267 | 268 | ; A2 -> B1 269 | move_value ebx, position_3, ebx, position_1 270 | 271 | ; C3 (saved) -> A3 272 | read_value_address ebx, position_2 273 | pop edi 274 | xchg eax, edi 275 | mov byte ptr [edi], al 276 | 277 | ; B3 -> A2 278 | move_value ecx, position_3, ebx, position_3 279 | 280 | ; C2 (saved) -> B3 281 | read_value_address ecx, position_3 282 | pop edi 283 | xchg eax, edi 284 | mov byte ptr [edi], al 285 | endm 286 | 287 | ; 288 | ; Execute the specified cube move 289 | ; 0 - move_F 6 - move_D c - move_R 290 | ; 1 - move_F_prime 7 - move_D_prime d - move_R_prime 291 | ; 2 - move_U 8 - move_M e - move_S 292 | ; 3 - move_U_prime 9 - move_M_prime f - move_S_prime 293 | ; 4 - move_L a - move_E g - move_B 294 | ; 5 - move_L_prime b - move_E_prime h - move_B_prime 295 | ; 296 | execute_move macro cube_state, cube_move 297 | push cube_state 298 | test cube_move, cube_move 299 | jnz @f_prime_move 300 | @f_move: 301 | nano_call n_move_F 302 | jmp @execute_move_exit 303 | 304 | @f_prime_move: 305 | dec cube_move 306 | test cube_move, cube_move 307 | jnz @u_move 308 | nano_call n_move_F_prime 309 | jmp @execute_move_exit 310 | 311 | @u_move: 312 | dec cube_move 313 | test cube_move, cube_move 314 | jnz @u_prime_move 315 | nano_call n_move_U 316 | jmp @execute_move_exit 317 | 318 | @u_prime_move: 319 | dec cube_move 320 | test cube_move, cube_move 321 | jnz @l_move 322 | nano_call n_move_U_prime 323 | jmp @execute_move_exit 324 | 325 | @l_move: 326 | dec cube_move 327 | test cube_move, cube_move 328 | jnz @l_prime_move 329 | nano_call n_move_L 330 | jmp @execute_move_exit 331 | 332 | @l_prime_move: 333 | dec cube_move 334 | test cube_move, cube_move 335 | jnz @d_move 336 | nano_call n_move_L_prime 337 | jmp @execute_move_exit 338 | 339 | @d_move: 340 | dec cube_move 341 | test cube_move, cube_move 342 | jnz @d_prime_move 343 | nano_call n_move_D 344 | jmp @execute_move_exit 345 | 346 | @d_prime_move: 347 | dec cube_move 348 | test cube_move, cube_move 349 | jnz @m_move 350 | nano_call n_move_D_prime 351 | jmp @execute_move_exit 352 | 353 | @m_move: 354 | dec cube_move 355 | test cube_move, cube_move 356 | jnz @m_prime_move 357 | nano_call n_move_M 358 | jmp @execute_move_exit 359 | 360 | @m_prime_move: 361 | dec cube_move 362 | test cube_move, cube_move 363 | jnz @e_move 364 | nano_call n_move_M_prime 365 | jmp @execute_move_exit 366 | 367 | @e_move: 368 | dec cube_move 369 | test cube_move, cube_move 370 | jnz @e_prime_move 371 | nano_call n_move_E 372 | jmp @execute_move_exit 373 | 374 | @e_prime_move: 375 | dec cube_move 376 | test cube_move, cube_move 377 | jnz @r_move 378 | nano_call n_move_E_prime 379 | jmp @execute_move_exit 380 | 381 | @r_move: 382 | dec cube_move 383 | test cube_move, cube_move 384 | jnz @r_prime_move 385 | nano_call n_move_R 386 | jmp @execute_move_exit 387 | 388 | @r_prime_move: 389 | dec cube_move 390 | test cube_move, cube_move 391 | jnz @s_move 392 | nano_call n_move_R_prime 393 | jmp @execute_move_exit 394 | 395 | @s_move: 396 | dec cube_move 397 | test cube_move, cube_move 398 | jnz @s_prime_move 399 | nano_call n_move_S 400 | jmp @execute_move_exit 401 | 402 | @s_prime_move: 403 | dec cube_move 404 | test cube_move, cube_move 405 | jnz @b_move 406 | nano_call n_move_S_prime 407 | jmp @execute_move_exit 408 | 409 | @b_move: 410 | dec cube_move 411 | test cube_move, cube_move 412 | jnz @b_prime_move 413 | nano_call n_move_B 414 | jmp @execute_move_exit 415 | 416 | @b_prime_move: 417 | dec cube_move 418 | test cube_move, cube_move 419 | jnz @execute_move_exit 420 | nano_call n_move_B_prime 421 | 422 | @execute_move_exit: 423 | pop cube_state 424 | endm 425 | 426 | ; 427 | ; Read and execute the next move if defined 428 | ; 429 | execute_next_move macro cube_state 430 | ; check if the pointer is set 431 | push eax 432 | mov eax, dword ptr [g_cube_moves] 433 | test eax, eax 434 | jz @execute_next_move_exit 435 | 436 | ; check if all moves have been executed 437 | cmp dword ptr [g_cube_moves_length], 0h 438 | jz @execute_next_move_exit 439 | 440 | ; execute the move and increment counter 441 | dec dword ptr [g_cube_moves_length] 442 | inc dword ptr [g_cube_moves] 443 | movzx eax, byte ptr [eax] 444 | execute_move cube_state, eax 445 | @execute_next_move_exit: 446 | pop eax 447 | endm 448 | 449 | ; ********************************** 450 | ; *** Effective Rubik Cube Moves *** 451 | ; ********************************** 452 | 453 | ; 454 | ; F move 455 | ; Parameters: cube buffer 456 | ; 457 | move_F proc 458 | push ebp 459 | mov ebp, esp 460 | 461 | mov ebx, 00010203h 462 | mov ecx, 04050607h 463 | mov edx, 08000000h 464 | mov esi, dword ptr [ebp+arg0] 465 | rotate_clockwise_faces 466 | 467 | ; move lateral faces 468 | mov ebx, 2a2b2c09h 469 | mov ecx, 0c0f2f2eh 470 | mov edx, 2d23201dh 471 | mov esi, dword ptr [ebp+arg0] 472 | shift_right_faces 473 | 474 | execute_next_move dword ptr [ebp+arg0] 475 | mov esp, ebp 476 | pop ebp 477 | ret 478 | move_F endp 479 | 480 | ; 481 | ; F' move 482 | ; Parameters: cube buffer 483 | ; 484 | move_F_prime proc 485 | push ebp 486 | mov ebp, esp 487 | 488 | ; move frontal faces 489 | mov ebx, 00010203h 490 | mov ecx, 04050607h 491 | mov edx, 08000000h 492 | mov esi, dword ptr [ebp+arg0] 493 | rotate_counterclockwise_faces 494 | 495 | ; move lateral faces 496 | mov ebx, 2a2b2c09h 497 | mov ecx, 0c0f2f2eh 498 | mov edx, 2d23201dh 499 | mov esi, dword ptr [ebp+arg0] 500 | shift_left_faces 501 | 502 | execute_next_move dword ptr [ebp+arg0] 503 | mov esp, ebp 504 | pop ebp 505 | ret 506 | move_F_prime endp 507 | 508 | ; 509 | ; R move 510 | ; Parameters: cube buffer 511 | ; 512 | move_R proc 513 | push ebp 514 | mov ebp, esp 515 | 516 | mov ebx, 0805022ch 517 | mov ecx, 29261215h 518 | mov edx, 1835322fh 519 | mov esi, dword ptr [ebp+arg0] 520 | shift_right_faces 521 | 522 | mov ebx, 090a0b0ch 523 | mov ecx, 0d0e0f10h 524 | mov edx, 11000000h 525 | mov esi, dword ptr [ebp+arg0] 526 | rotate_clockwise_faces 527 | 528 | execute_next_move dword ptr [ebp+arg0] 529 | mov esp, ebp 530 | pop ebp 531 | ret 532 | move_R endp 533 | 534 | ; 535 | ; R' move 536 | ; Parameters: cube buffer 537 | ; 538 | move_R_prime proc 539 | push ebp 540 | mov ebp, esp 541 | 542 | mov ebx, 0805022ch 543 | mov ecx, 29261215h 544 | mov edx, 1835322fh 545 | mov esi, dword ptr [ebp+arg0] 546 | shift_left_faces 547 | 548 | ; move frontal faces 549 | mov ebx, 090a0b0ch 550 | mov ecx, 0d0e0f10h 551 | mov edx, 11000000h 552 | mov esi, dword ptr [ebp+arg0] 553 | rotate_counterclockwise_faces 554 | 555 | execute_next_move dword ptr [ebp+arg0] 556 | mov esp, ebp 557 | pop ebp 558 | ret 559 | move_R_prime endp 560 | 561 | ; 562 | ; U move 563 | ; Parameters: cube buffer 564 | ; 565 | move_U proc 566 | push ebp 567 | mov ebp, esp 568 | 569 | mov ebx, 00010209h 570 | mov ecx, 0a0b1213h 571 | mov edx, 141b1c1dh 572 | mov esi, dword ptr [ebp+arg0] 573 | shift_left_faces 574 | 575 | ; move frontal faces 576 | mov ebx, 24252627h 577 | mov ecx, 28292a2bh 578 | mov edx, 2c000000h 579 | mov esi, dword ptr [ebp+arg0] 580 | rotate_clockwise_faces 581 | 582 | execute_next_move dword ptr [ebp+arg0] 583 | mov esp, ebp 584 | pop ebp 585 | ret 586 | move_U endp 587 | 588 | ; 589 | ; U' move 590 | ; Parameters: cube buffer 591 | ; 592 | move_U_prime proc 593 | push ebp 594 | mov ebp, esp 595 | 596 | mov ebx, 00010209h 597 | mov ecx, 0a0b1213h 598 | mov edx, 141b1c1dh 599 | mov esi, dword ptr [ebp+arg0] 600 | shift_right_faces 601 | 602 | mov ebx, 24252627h 603 | mov ecx, 28292a2bh 604 | mov edx, 2c000000h 605 | mov esi, dword ptr [ebp+arg0] 606 | rotate_counterclockwise_faces 607 | 608 | execute_next_move dword ptr [ebp+arg0] 609 | mov esp, ebp 610 | pop ebp 611 | ret 612 | move_U_prime endp 613 | 614 | ; 615 | ; L move 616 | ; Parameters: cube buffer 617 | ; 618 | move_L proc 619 | push ebp 620 | mov ebp, esp 621 | 622 | mov ebx, 0603002ah 623 | mov ecx, 27241417h 624 | mov edx, 1a33302dh 625 | mov esi, dword ptr [ebp+arg0] 626 | shift_left_faces 627 | 628 | mov ebx, 1d20231ch 629 | mov ecx, 1f221b1eh 630 | mov edx, 21000000h 631 | mov esi, dword ptr [ebp+arg0] 632 | rotate_clockwise_faces 633 | 634 | execute_next_move dword ptr [ebp+arg0] 635 | mov esp, ebp 636 | pop ebp 637 | ret 638 | move_L endp 639 | 640 | ; 641 | ; L' move 642 | ; Parameters: cube buffer 643 | ; 644 | move_L_prime proc 645 | push ebp 646 | mov ebp, esp 647 | 648 | mov ebx, 0603002ah 649 | mov ecx, 27241417h 650 | mov edx, 1a33302dh 651 | mov esi, dword ptr [ebp+arg0] 652 | shift_right_faces 653 | 654 | mov ebx, 1d20231ch 655 | mov ecx, 1f221b1eh 656 | mov edx, 21000000h 657 | mov esi, dword ptr [ebp+arg0] 658 | rotate_counterclockwise_faces 659 | 660 | execute_next_move dword ptr [ebp+arg0] 661 | mov esp, ebp 662 | pop ebp 663 | ret 664 | move_L_prime endp 665 | 666 | ; 667 | ; D move 668 | ; Parameters: cube buffer 669 | ; 670 | move_D proc 671 | push ebp 672 | mov ebp, esp 673 | 674 | mov ebx, 0607080fh 675 | mov ecx, 10111819h 676 | mov edx, 1a212223h 677 | mov esi, dword ptr [ebp+arg0] 678 | shift_right_faces 679 | 680 | mov ebx, 2d2e2f30h 681 | mov ecx, 31323334h 682 | mov edx, 35000000h 683 | mov esi, dword ptr [ebp+arg0] 684 | rotate_clockwise_faces 685 | 686 | execute_next_move dword ptr [ebp+arg0] 687 | mov esp, ebp 688 | pop ebp 689 | ret 690 | move_D endp 691 | 692 | ; 693 | ; D' move 694 | ; Parameters: cube buffer 695 | ; 696 | move_D_prime proc 697 | push ebp 698 | mov ebp, esp 699 | 700 | mov ebx, 0607080fh 701 | mov ecx, 10111819h 702 | mov edx, 1a212223h 703 | mov esi, dword ptr [ebp+arg0] 704 | shift_left_faces 705 | 706 | mov ebx, 2d2e2f30h 707 | mov ecx, 31323334h 708 | mov edx, 35000000h 709 | mov esi, dword ptr [ebp+arg0] 710 | rotate_counterclockwise_faces 711 | 712 | execute_next_move dword ptr [ebp+arg0] 713 | mov esp, ebp 714 | pop ebp 715 | ret 716 | move_D_prime endp 717 | 718 | ; 719 | ; B move 720 | ; Parameters: cube buffer 721 | ; 722 | move_B proc 723 | push ebp 724 | mov ebp, esp 725 | 726 | mov ebx, 14131217h 727 | mov ecx, 16151a19h 728 | mov edx, 18000000h 729 | mov esi, dword ptr [ebp+arg0] 730 | rotate_counterclockwise_faces 731 | 732 | ; move lateral faces 733 | mov ebx, 26252411h 734 | mov ecx, 0e0b3334h 735 | mov edx, 351b1e21h 736 | mov esi, dword ptr [ebp+arg0] 737 | shift_left_faces 738 | 739 | execute_next_move dword ptr [ebp+arg0] 740 | mov esp, ebp 741 | pop ebp 742 | ret 743 | move_B endp 744 | 745 | ; 746 | ; B' move 747 | ; Parameters: cube buffer 748 | ; 749 | move_B_prime proc 750 | push ebp 751 | mov ebp, esp 752 | 753 | mov ebx, 14131217h 754 | mov ecx, 16151a19h 755 | mov edx, 18000000h 756 | mov esi, dword ptr [ebp+arg0] 757 | rotate_clockwise_faces 758 | 759 | ; move lateral faces 760 | mov ebx, 26252411h 761 | mov ecx, 0e0b3334h 762 | mov edx, 351b1e21h 763 | mov esi, dword ptr [ebp+arg0] 764 | shift_right_faces 765 | 766 | execute_next_move dword ptr [ebp+arg0] 767 | mov esp, ebp 768 | pop ebp 769 | ret 770 | move_B_prime endp 771 | 772 | ; 773 | ; S move 774 | ; Parameters: cube buffer 775 | ; 776 | move_S proc 777 | push ebp 778 | mov ebp, esp 779 | 780 | ; move lateral faces 781 | mov ebx, 2728290ah 782 | mov ecx, 0d103231h 783 | mov edx, 30221f1ch 784 | mov esi, dword ptr [ebp+arg0] 785 | shift_right_faces 786 | 787 | execute_next_move dword ptr [ebp+arg0] 788 | mov esp, ebp 789 | pop ebp 790 | ret 791 | move_S endp 792 | 793 | ; 794 | ; S' move 795 | ; Parameters: cube buffer 796 | ; 797 | move_S_prime proc 798 | push ebp 799 | mov ebp, esp 800 | 801 | ; move lateral faces 802 | mov ebx, 2728290ah 803 | mov ecx, 0d103231h 804 | mov edx, 30221f1ch 805 | mov esi, dword ptr [ebp+arg0] 806 | shift_left_faces 807 | 808 | execute_next_move dword ptr [ebp+arg0] 809 | mov esp, ebp 810 | pop ebp 811 | ret 812 | move_S_prime endp 813 | 814 | ; 815 | ; M move 816 | ; Parameters: cube buffer 817 | ; 818 | move_M proc 819 | push ebp 820 | mov ebp, esp 821 | 822 | mov ebx, 0704012bh 823 | mov ecx, 28251316h 824 | mov edx, 1934312eh 825 | mov esi, dword ptr [ebp+arg0] 826 | shift_left_faces 827 | 828 | execute_next_move dword ptr [ebp+arg0] 829 | mov esp, ebp 830 | pop ebp 831 | ret 832 | move_M endp 833 | 834 | ; 835 | ; M' move 836 | ; Parameters: cube buffer 837 | ; 838 | move_M_prime proc 839 | push ebp 840 | mov ebp, esp 841 | 842 | mov ebx, 0704012bh 843 | mov ecx, 28251316h 844 | mov edx, 1934312eh 845 | mov esi, dword ptr [ebp+arg0] 846 | shift_right_faces 847 | 848 | execute_next_move dword ptr [ebp+arg0] 849 | mov esp, ebp 850 | pop ebp 851 | ret 852 | move_M_prime endp 853 | 854 | ; 855 | ; E move 856 | ; Parameters: cube buffer 857 | ; 858 | move_E proc 859 | push ebp 860 | mov ebp, esp 861 | 862 | mov ebx, 0304050ch 863 | mov ecx, 0d0e1516h 864 | mov edx, 171e1f20h 865 | mov esi, dword ptr [ebp+arg0] 866 | shift_right_faces 867 | 868 | execute_next_move dword ptr [ebp+arg0] 869 | mov esp, ebp 870 | pop ebp 871 | ret 872 | move_E endp 873 | 874 | ; 875 | ; E' move 876 | ; Parameters: cube buffer 877 | ; 878 | move_E_prime proc 879 | push ebp 880 | mov ebp, esp 881 | 882 | mov ebx, 0304050ch 883 | mov ecx, 0d0e1516h 884 | mov edx, 171e1f20h 885 | mov esi, dword ptr [ebp+arg0] 886 | shift_left_faces 887 | 888 | execute_next_move dword ptr [ebp+arg0] 889 | mov esp, ebp 890 | pop ebp 891 | ret 892 | move_E_prime endp --------------------------------------------------------------------------------