commit bb352c151106cf688f8bfdd7be198d8d76fc6eab Author: Double Sine Date: Thu Oct 25 13:25:30 2018 +0800 Upload code and README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef139fe --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Custom.mxtpro diff --git a/MobaXterm-Keygen.py b/MobaXterm-Keygen.py new file mode 100644 index 0000000..86d0ba7 --- /dev/null +++ b/MobaXterm-Keygen.py @@ -0,0 +1,126 @@ +#/usr/bin/env python3 +''' +Author: Double Sine +License: GPLv3 +''' +import os, sys, zipfile + +VariantBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' +VariantBase64Dict = { i : VariantBase64Table[i] for i in range(len(VariantBase64Table)) } +VariantBase64ReverseDict = { VariantBase64Table[i] : i for i in range(len(VariantBase64Table)) } + +def VariantBase64Encode(bs : bytes): + result = b'' + blocks_count, left_bytes = divmod(len(bs), 3) + + for i in range(blocks_count): + coding_int = int.from_bytes(bs[3 * i:3 * i + 3], 'little') + block = VariantBase64Dict[coding_int & 0x3f] + block += VariantBase64Dict[(coding_int >> 6) & 0x3f] + block += VariantBase64Dict[(coding_int >> 12) & 0x3f] + block += VariantBase64Dict[(coding_int >> 18) & 0x3f] + result += block.encode() + + if left_bytes == 0: + return result + elif left_bytes == 1: + coding_int = int.from_bytes(bs[3 * blocks_count:], 'little') + block = VariantBase64Dict[coding_int & 0x3f] + block += VariantBase64Dict[(coding_int >> 6) & 0x3f] + result += block.encode() + return result + else: + coding_int = int.from_bytes(bs[3 * blocks_count:], 'little') + block = VariantBase64Dict[coding_int & 0x3f] + block += VariantBase64Dict[(coding_int >> 6) & 0x3f] + block += VariantBase64Dict[(coding_int >> 12) & 0x3f] + result += block.encode() + return result + +def VariantBase64Decode(s : str): + result = b'' + blocks_count, left_bytes = divmod(len(s), 4) + + for i in range(blocks_count): + block = VariantBase64ReverseDict[s[4 * i]] + block += VariantBase64ReverseDict[s[4 * i + 1]] << 6 + block += VariantBase64ReverseDict[s[4 * i + 2]] << 12 + block += VariantBase64ReverseDict[s[4 * i + 3]] << 18 + result += block.to_bytes(3, 'little') + + if left_bytes == 0: + return result + elif left_bytes == 2: + block = VariantBase64ReverseDict[s[4 * blocks_count]] + block += VariantBase64ReverseDict[s[4 * blocks_count + 1]] << 6 + result += block.to_bytes(1, 'little') + return result + elif left_bytes == 3: + block = VariantBase64ReverseDict[s[4 * blocks_count]] + block += VariantBase64ReverseDict[s[4 * blocks_count + 1]] << 6 + block += VariantBase64ReverseDict[s[4 * blocks_count + 2]] << 12 + result += block.to_bytes(2, 'little') + return result + else: + raise ValueError('Invalid encoding.') + +def EncryptBytes(key : int, bs : bytes): + result = bytearray() + for i in range(len(bs)): + result.append(bs[i] ^ ((key >> 8) & 0xff)) + key = result[-1] & key | 0x482D + return bytes(result) + +def DecryptBytes(key : int, bs : bytes): + result = bytearray() + for i in range(len(bs)): + result.append(bs[i] ^ ((key >> 8) & 0xff)) + key = bs[i] & key | 0x482D + return bytes(result) + +class LicenseType: + Professional = 1 + Educational = 3 + Persional = 4 + +def GenerateLicense(Type : LicenseType, Count : int, UserName : str, MajorVersion : int, MinorVersion): + assert(Count >= 0) + LicenseString = '%d#%s|%d%d#%d#%d3%d6%d#%d#%d#%d#' % (Type, + UserName, MajorVersion, MinorVersion, + Count, + MajorVersion, MinorVersion, MinorVersion, + 0, # Unknown + 0, # No Games flag. 0 means "NoGames = false". But it does not work. + 0) # No Plugins flag. 0 means "NoPlugins = false". But it does not work. + EncodedLicenseString = VariantBase64Encode(EncryptBytes(0x787, LicenseString.encode())).decode() + with zipfile.ZipFile('Custom.mxtpro', 'w') as f: + f.writestr('Pro.key', data = EncodedLicenseString) + +def help(): + print('Usage:') + print(' MobaXterm-Keygen.py ') + print() + print(' : The Name licensed to') + print(' : The Version of MobaXterm') + print(' Example: 10.9') + print() + +if __name__ == '__main__': + if len(sys.argv) != 3: + help() + exit(0) + else: + MajorVersion, MinorVersion = sys.argv[2].split('.')[0:2] + MajorVersion = int(MajorVersion) + MinorVersion = int(MinorVersion) + GenerateLicense(LicenseType.Professional, + 1, + sys.argv[1], + MajorVersion, + MinorVersion) + print('[*] Success!') + print('[*] File generated: %s' % os.path.join(os.getcwd(), 'Custom.mxtpro')) + print('[*] Please move or copy the newly-generated file to MobaXterm\'s installation path.') + print() +else: + print('[*] ERROR: Please run this script directly') diff --git a/README.md b/README.md new file mode 100644 index 0000000..0dafab8 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# MobaXterm Keygen + +## How it work? + +Please see source code. It is not complex. + +## How to use? + +``` +Usage: + MobaXterm-Keygen.py + + : The Name licensed to + : The Version of MobaXterm + Example: 10.9 +``` + +EXAMPLE: + +``` +PS C:\Users\DoubleSine\Github\MobaXterm-Keygen> .\MobaXterm-Keygen.py "DoubleSine" 10.9 +[*] Success! +[*] File generated: C:\Users\DoubleSine\Github\MobaXterm-Keygen\Custom.mxtpro +[*] Please move or copy the newly-generated file to MobaXterm's installation path. +``` + +Then copy `Custom.mxtpro` to `C:\Program Files (x86)\Mobatek\MobaXterm`. + +## Screenshot + +![](pic0.png) + +## Postscript + +1. This application does not have complex activation algorithm and it is truly fantastic. __So please pay for it if possible.__ + +2. The file generated, `Custom.mxtpro`, is actually a zip file and contains a text file, `Pro.key`, where there is a key string. + +3. `MobaXterm.exe` has another mode. You can see it by adding a parameter `"-customizer"`. + + ``` + $ .\MobaXterm.exe -customizer + ``` + + I don't know how to make custom settings take effect in `Customizer` mode directly. + + The only way I found is that you should export custom settings to a file named `MobaXterm customization.custom` which is also a zip file. Then merge two zip file: `Custom.mxtpro` and `MobaXterm customization.custom` to `Custom.mxtpro`. Finally copy newly-generated `Custom.mxtpro` to MobaXterm's installation path. + diff --git a/pic0.png b/pic0.png new file mode 100644 index 0000000..8700076 Binary files /dev/null and b/pic0.png differ