├── 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
--------------------------------------------------------------------------------