{"id":709,"date":"2013-10-02T22:11:17","date_gmt":"2013-10-02T20:11:17","guid":{"rendered":"http:\/\/blog.rewolf.pl\/blog\/?p=709"},"modified":"2013-10-02T22:26:11","modified_gmt":"2013-10-02T20:26:11","slug":"solving-redbeansoups-1st-crackme-ironpython","status":"publish","type":"post","link":"http:\/\/blog.rewolf.pl\/blog\/?p=709","title":{"rendered":"Solving RedBeanSoup&#8217;s 1st Crackme (IronPython)"},"content":{"rendered":"<p style=\"text-align: justify;\">I&#8217;ve solved this little crackme quite some time ago, but I haven&#8217;t had time to publish the results. Besides this, protection wasn&#8217;t too hard, so I wasn&#8217;t sure if there is really anything to publish. Crackme was published on <em>14 January 2010<\/em> on <a href=\"http:\/\/crackmes.de\/users\/redbeansoup\/redbeansoups_first_crackme\/\" title=\"crackmes.de\" target=\"_blank\">crackmes.de<\/a>, difficulty was set to 3 (<em>Getting harder<\/em>). Honestly speaking, without <strong><a href=\"http:\/\/ironpython.net\/\" title=\"IronPython\" target=\"_blank\">IronPython<\/a><\/strong> I would say that difficulty of this crackme is 1 (<em>Very easy, for newbies<\/em>, in the terms of crackmes.de scale), but with <strong>IronPython<\/strong>&#8230; well, it proved to be hard enough for me. Below analysis will shed some light on <strong>IronPython <\/strong>internals, there will be also part about <strong>.NET<\/strong> (as <strong>IronPython <\/strong>is just <strong>.NET Python<\/strong>), I&#8217;ll also cover the protection part, but it will not take too much space.<\/p>\n<p><!--more--><\/p>\n<h3>IronPython<\/h3>\n<p style=\"text-align: justify;\">I&#8217;ll not describe <strong>IronPython <\/strong>in general, but this specific case, so things may vary for different executables. Crackme is shipped as a zip package and contains 9 files:<\/p>\n<pre>    CrackMe1.dll\r\n    CrackMe1.exe\r\n    IronPython.dll\r\n    IronPython.xml\r\n    Microsoft.Dynamic.dll\r\n    Microsoft.Scripting.Core.dll\r\n    Microsoft.Scripting.Debugging.dll\r\n    Microsoft.Scripting.dll\r\n    Microsoft.Scripting.ExtensionAttribute.dll\r\n<\/pre>\n<p style=\"text-align: justify;\"><em>Microsoft.*.dlls<\/em> are part of <strong><a href=\"http:\/\/dlr.codeplex.com\/\" title=\"Dynamic Language Runtime\" target=\"_blank\">Dynamic Language Runtime<\/a><\/strong> (<strong>DLR<\/strong>) that runs on top of the <strong>.NET<\/strong> framework, <em>IronPython.dll<\/em> is <strong>IronPython <\/strong>runtime (with some .xml config). Crackme itself is split into two parts, executable and dll. Executable is just a host application that runs the proper module from the DLL:<\/p>\n<pre lang=\"csharp\">\/\/ PythonMain\r\n[STAThread]\r\npublic static int Main()\r\n{\r\n  return PythonOps.InitializeModule(Assembly.LoadFile(Path.GetFullPath(\"CrackMe1.dll\")), \"Program\", new string[]\r\n  {\r\n    \"IronPython, Version=2.6.10920.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\",\r\n    \"mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\r\n    \"System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\r\n    \"System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\r\n    \"System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\",\r\n    \"System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\r\n    \"System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\r\n\t});\r\n}\r\n<\/pre>\n<p style=\"text-align: justify;\">So, analysis will be done only on <em>CrackMe1.dll<\/em>. It contains only one class called <strong>DLRCachedCode<\/strong>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ironpython_pic1.png\" alt=\"ironpython_pic1\" width=\"515\" height=\"326\" class=\"aligncenter size-full wp-image-715\" srcset=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ironpython_pic1.png 515w, http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ironpython_pic1-300x189.png 300w\" sizes=\"(max-width: 515px) 100vw, 515px\" \/><\/p>\n<p style=\"text-align: justify;\">As you can see names are not obfuscated, which seems very promising, especially function names like <strong>CheckKey$17()<\/strong> or <strong>KeyEncrypt$16()<\/strong>. Unfortunately code generated by <strong>IronPython <\/strong>compiler is more than enough in the term of <em>obfuscation<\/em>. All functions and objects are accessed through <em>System.Runtime.CompilerServices.CallSite<\/em> template class, for example:<\/p>\n<pre lang=\"csharp\">  \/\/Part of the KeyEncrypt$16() function\r\n  CallSite<Func<CallSite, object, CodeContext, object>> arg7;\r\n  object arg6 = (arg7 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[284]).Target(arg7, arg4, globalContext);\r\n  line = 126;\r\n  CallSite<Func<CallSite, CodeContext, object, string, object>> arg9;\r\n  CallSite<Func<CallSite, object, CodeContext, object>> arg10;\r\n  object arg8 = (arg9 = (CallSite<Func<CallSite, CodeContext, object, string, object>>)strongBox.Value[285]).Target(arg9, globalContext, (arg10 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[286]).Target(arg10, arg2, globalContext), \"09887778\");\r\n  line = 127;\r\n  CallSite<Func<CallSite, object, object, object>> arg11;\r\n  CallSite<Func<CallSite, CodeContext, object, string, object>> arg12;\r\n  CallSite<Func<CallSite, object, CodeContext, object>> arg13;\r\n  (arg11 = (CallSite<Func<CallSite, object, object, object>>)strongBox.Value[287]).Target(arg11, arg4, (arg12 = (CallSite<Func<CallSite, CodeContext, object, string, object>>)strongBox.Value[288]).Target(arg12, globalContext, (arg13 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[289]).Target(arg13, arg2, globalContext), \"redbeansredbeans\"));\r\n<\/pre>\n<p style=\"text-align: justify;\">Static analysis of this code is pretty much impossible, only some partial information can be gathered (code flow, strings, names of <strong>.NET<\/strong> objects). There is also one cool feature that gives some information about the original python code. In the above snippet there are assignments like <em>&#8220;line = 126;&#8221;<\/em>, those are line numbers from the original python script. Quick look at the <strong>#US<\/strong> (user string heap) stream from <strong>.NET<\/strong> image reveals some useful informations:<\/p>\n<pre>00000CF8: #US\r\n\t...\r\n        You must register to fully enjoy this software.\r\n\t...\r\n        Later, I'm Too Poor\r\n\t...\r\n        RedBeanSoup\r\n\t...\r\n        Thank you!\r\n        Accepted\r\n         - Registered to\r\n        Please check your registration information try again.\r\n        Invalid Key\r\n\t...\r\n        09887778\r\n        redbeansredbeans\r\n\t...\r\n        UTF8Encoding\r\n        RijndaelManaged\r\n        CryptoStream\r\n        CryptoStreamMode\r\n\t...\r\n        blocksize\r\n        key\r\n        text\r\n        crypt\r\n        \/+=\r\n        -\r\n        Fully Registered Version\r\n        finalkey\r\n\t...\r\n        BlockSize\r\n        GetBytes\r\n        IV\r\n        translate\r\n        strip\r\n        CreateEncryptor\r\n\t...\r\n        Serial\r\n        ToBase64String\r\n\t...\r\n        iv\r\n        ToUpper\r\n\t...\r\n<\/pre>\n<p style=\"text-align: justify;\">Judging only by those strings, I can tell that there will be <strong>Rijndael<\/strong> (<em>&#8220;RijndaelManaged&#8221;<\/em>, <em>&#8220;BlockSize&#8221;<\/em>, <em>&#8220;IV&#8221;<\/em>) and <strong>Base64 <\/strong>(<em>&#8220;ToBase64String&#8221;<\/em>) algorithms involved. There are also some fancy strings like <em>&#8220;09887778&#8221;<\/em> or <em>&#8220;redbeansredbeans&#8221;<\/em>, that might be somehow related to the serial number generation. At that point I&#8217;ve stuck, so I had to switch to dynamic analysis.<\/p>\n<h3>.NET Profiling<\/h3>\n<p style=\"text-align: justify;\">Having some bad experience with <strong>.NET<\/strong> bytecode debuggers in the past, I decided to give a try to <strong>.NET profiling API<\/strong>. There is a nice article about this topic written by <em>Matt Pietrek<\/em> and dated back to 2001 year:<\/p>\n<p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/magazine\/cc301725.aspx\" target=\"_blank\">http:\/\/msdn.microsoft.com\/en-us\/magazine\/cc301725.aspx<\/a><\/p>\n<p style=\"text-align: justify;\">It describes all the basic stuff behind <strong>.NET<\/strong> profiling and as a bonus it contains source code of simple profiler called <strong>DNProfiler<\/strong>. Link to the source code is broken, but I managed to put my dirty hands on it :) so here is the link to the original package:<\/p>\n<p><a href=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/Hood0112.zip\" target=\"_blank\">Hood0112.zip<\/a><\/p>\n<p style=\"text-align: justify;\">As those sources are 12 years old, they&#8217;re a bit outdated. Sample from the article is using <strong>ICorProfilerCallback<\/strong> while there is already <strong>ICorProfilerCallback4<\/strong> (since <strong>.NET 4<\/strong>). Crackme is compiled for <strong>.NET 2.0<\/strong>, so I&#8217;ve updated this project to use <strong>ICorProfilerCallback2<\/strong>. <strong>.NET profiling API<\/strong> enables user to trace all entries and exits from every function (user defined as well as <strong>.NET<\/strong> runtime). Mentioned project doesn&#8217;t implement those hooks, but I&#8217;ve added it to gather some information about execution path. Below you can find patches that I&#8217;ve made to the project:<\/p>\n<p><a href=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ProfilerCallback.patch_.txt\" target=\"_blank\">ProfilerCallback.patch<\/a><\/p>\n<p style=\"text-align: justify;\">Amount of data gathered by this tool is unbelievable, when all hooks are enabled (<em>enter\/leave<\/em> for every function) there is also huge slowdown. It would be possible to skip generation of some data, and filter output to collect only information useful from the crackme solver point of view, but honestly speaking it overwhelmed me a bit so I dropped that idea. Sample output:<\/p>\n<pre>  ModuleLoadFinished: X:\\xxx\\RbsCrackMe1\\CrackMe1.dll\r\n  ModuleAttachedToAssembly: CrackMe1\r\nAssemblyLoadFinished: CrackMe1  Status: 00000000\r\nObjectAllocated: array of System.String\r\nJITCompilationStarted: IronPython.Runtime.Operations.PythonOps::.cctor\r\n  AssemblyLoadStarted\r\n    ModuleLoadStarted\r\n      ObjectAllocated: array of System.Object\r\n      HandleCreated\r\n      HandleCreated\r\n      HandleCreated\r\n      HandleCreated\r\n      ObjectAllocated: System.Reflection.Assembly\r\n      FunctionEnter: System.Reflection.Assembly::IsAssemblyUnderAppBase\r\n      FunctionEnter: System.Reflection.Assembly::GetLocation\r\n      FunctionEnter: System.Reflection.Assembly::get_InternalAssembly\r\n      ObjectAllocated: System.String\r\n<\/pre>\n<p style=\"text-align: justify;\">Due to lack of time and other stuff that was waiting I&#8217;ve stopped playing with this profiling stuff and decided to move on.<\/p>\n<h3>ILSpy Debugger<\/h3>\n<p style=\"text-align: justify;\"><strong>ILSpy <\/strong>debugger worked surprisingly well on this crackme, there was one minor issue, namely it wasn&#8217;t working on <em>x64 Windows<\/em>, so I had to use it inside <strong>VMWare<\/strong>. I was debugging on <strong>C#-level<\/strong> as it was way more convenient than <strong>IL-level<\/strong>. There are basically two functions that needs to be traced: <strong>KeyEncrypt$16()<\/strong> and <strong>CheckKey$17()<\/strong>. <strong>KeyEncrypt$16()<\/strong> triggers first, debugging this code might be a bit complicated, but the bottom line is just about looking at the values\/objects returned from all those cryptic <strong>CallSites<><\/strong> calls. During debugging there are a lot of references to the array of objects called <strong>strongBox.Value[n]<\/strong>, this array is initialized inside <strong>MainForm$7()<\/strong> function. It is easier to check indexes in this array from the <strong>Reflector<\/strong>, because <strong>ILSpy <\/strong>decompiles it as a proper array initialization and <strong>Reflector <\/strong>generates assignment operator for every array element:<\/p>\n<pre lang=\"csharp\">\/\/ILSpy:\r\n    object[] value = new object[]\r\n    {\r\n        \/\/...\r\n        CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, \"BlockSize\", false)),\r\n        CallSite<Func<CallSite, CodeContext, object, string, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(1))),\r\n        CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, \"GetBytes\", false)),\r\n        CallSite<Func<CallSite, object, object, object>>.Create(PythonOps.MakeSetAction($globalContext, \"IV\")),\r\n        \/\/...\r\n    };\r\n    ((StrongBox<object[]>)array[0]).Value = value;\r\n\r\n\/\/Reflector\r\n    object[] objArray3 = new object[0x15a];\r\n    objArray3[0x11c] = CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, \"BlockSize\", false));\r\n    objArray3[0x11d] = CallSite<Func<CallSite, CodeContext, object, string, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(1)));\r\n    objArray3[0x11e] = CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, \"GetBytes\", false));\r\n    objArray3[0x11f] = CallSite<Func<CallSite, object, object, object>>.Create(PythonOps.MakeSetAction($globalContext, \"IV\"));\r\n    object[] objArray2 = objArray3;\r\n    ((StrongBox<object[]>) objArray[0]).Value = objArray2;\r\n<\/pre>\n<p style=\"text-align: justify;\">Below there are some most interesting values from this array:<\/p>\n<pre>strongBox.Value[284] -> \"BlockSize\"\r\nstrongBox.Value[286] -> \"GetBytes\"\r\nstrongBox.Value[287] -> \"IV\"\r\nstrongBox.Value[289] -> \"GetBytes\r\nstrongBox.Value[291] -> \"_textBox1\"\r\nstrongBox.Value[293] -> \"translate\"\r\nstrongBox.Value[295] -> \"strip\"\r\nstrongBox.Value[297] -> \"_textBox1\"\r\nstrongBox.Value[299] -> \"GetBytes\"\r\nstrongBox.Value[301] -> \"_textBox1\"\r\nstrongBox.Value[304] -> \"CreateEncryptor\"\r\nstrongBox.Value[305] -> \"IV\"\r\nstrongBox.Value[311] -> \"FlushFinalBlock\"\r\nstrongBox.Value[314] -> \"ToBase64String\"\r\nstrongBox.Value[317] -> \"iv\"\r\nstrongBox.Value[320] -> \"CheckKey\"\r\nstrongBox.Value[322] -> \"ToUpper\"\r\nstrongBox.Value[325] -> \"translate\"\r\n<\/pre>\n<p style=\"text-align: justify;\">There is also second global array that is worth to note (let&#8217;s call it <strong>globalArray<\/strong>):<\/p>\n<pre lang=\"csharp\">PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext(globalContext);\r\n<\/pre>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ironpython_pic2.png\" alt=\"ironpython_pic2\" width=\"603\" height=\"253\" class=\"aligncenter size-full wp-image-724\" srcset=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ironpython_pic2.png 603w, http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/ironpython_pic2-300x125.png 300w\" sizes=\"(max-width: 603px) 100vw, 603px\" \/><\/p>\n<p style=\"text-align: justify;\">Having all those information ready I can start proper debugging. <strong>KeyEncrypt$16()<\/strong> creates new <strong>RijndaelManaged <\/strong>object, and sets explicitly <strong>BlockSize<\/strong> to <strong>128<\/strong>. Next it converts <em>&#8220;09887778&#8221;<\/em> string to byte array (<strong>GetBytes<\/strong>). Following line reference <strong>&#8220;IV&#8221;<\/strong> and <strong>&#8220;GetBytes&#8221;<\/strong> from the <strong>strongBox <\/strong>array and <em>&#8220;redbeansredbeans&#8221;<\/em> string from the <strong>#US<\/strong> stream, I&#8217;ve assumed that it sets the initialization vector <strong>IV<\/strong> to <em>&#8220;redbeansredbeans&#8221;<\/em>. In the next step crackme performs <strong>strip()<\/strong> and <strong>translate()<\/strong> operations from <strong>python <\/strong>runtime on the <strong>&#8220;_textBox1&#8221;<\/strong> which contains entered user-name. All gathered information are put into <strong>CreateEncryptor <\/strong>function (from <strong>RijndalManaged <\/strong>object) and written into <strong>CryptoStream <\/strong>object. Below code represents what is happening (it is part of the keygen, so it is not 1:1 code from the crackme):<\/p>\n<pre lang=\"csharp\">  System.Text.ASCIIEncoding ascenc = new System.Text.ASCIIEncoding();\r\n  RijndaelManaged rm = new RijndaelManaged();\r\n  rm.BlockSize = 128;\r\n  rm.KeySize = 256;\r\n  ICryptoTransform ict = rm.CreateEncryptor(ascenc.GetBytes(\"09887778\"), ascenc.GetBytes(\"redbeansredbeans\"));\r\n\r\n  string name = (0 == args.Length) ? \"ReWolf\" : args[0];\r\n\r\n  byte[] result;\r\n  using (MemoryStream msEncrypt = new MemoryStream())\r\n  {\r\n    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, ict, CryptoStreamMode.Write))\r\n    {\r\n      using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))\r\n      {\r\n        swEncrypt.Write(name);\r\n      }\r\n      result = msEncrypt.GetBuffer();\r\n    }\r\n  }\r\n<\/pre>\n<p style=\"text-align: justify;\">The last thing before call to <strong>CheckKey$17()<\/strong> is conversion of encrypted stream to <strong>base64 <\/strong>(<strong>Convert.ToBase64String()<\/strong>). <strong>CheckKey$17()<\/strong> is fairly easy to analyse, at first it makes generated <strong>base64 <\/strong>string uppercase (<strong>ToUpper<\/strong>), next it calls python runtime function called <strong>translate()<\/strong> which strips <strong>base64 <\/strong>output from this three characters <em>&#8220;\/+=&#8221;<\/em>. <strong>CheckKey$17()<\/strong> gets only 16 characters from the output string. Those characters are split into four groups and separated with <em>&#8220;-&#8220;<\/em>. This new string is compared to entered serial number, yes <strong>the whole protection is just strcmp&#8230;<\/strong> Below you can find link to the keygen (written in <strong>C#<\/strong>):<\/p>\n<p><a href=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/rwf_rbs_keygen.cs_.txt\" target=\"_blank\">rwf_rbs_keygen.cs<\/a><br \/>\n<a href=\"http:\/\/blog.rewolf.pl\/blog\/wp-content\/uploads\/2013\/10\/rbs_keygen.zip\" target=\"_blank\">rbs_keygen.zip<\/a><\/p>\n<p style=\"text-align: justify;\">I hope you enjoyed this analysis even though it was just plain strcmp.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve solved this little crackme quite some time ago, but I haven&#8217;t had time to publish the results. Besides this, protection wasn&#8217;t too hard, so I wasn&#8217;t sure if there is really anything to publish. Crackme was published on 14 January 2010 on crackmes.de, difficulty was set to 3 (Getting harder). Honestly speaking, without IronPython [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[14,15,13,3],"tags":[],"_links":{"self":[{"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=\/wp\/v2\/posts\/709"}],"collection":[{"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=709"}],"version-history":[{"count":37,"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=\/wp\/v2\/posts\/709\/revisions"}],"predecessor-version":[{"id":754,"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=\/wp\/v2\/posts\/709\/revisions\/754"}],"wp:attachment":[{"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=709"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=709"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.rewolf.pl\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=709"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}