tag:blogger.com,1999:blog-22209118812895771062024-03-22T03:04:58.293+00:00Chaos to Order?Unknownnoreply@blogger.comBlogger21125tag:blogger.com,1999:blog-2220911881289577106.post-78081803868243307462007-12-12T16:22:00.000+00:002007-12-12T16:25:51.566+00:00Not so Static Classes?A colleague of mine noticed something interesting whilst working with C# the other day.<br />He had a breakpoint in a static constructor (on a non-static class) which seemed to be hit several times during execution of his program.<br />He discussed this with me and we both agreed that in C# it should not be possible for a static constructor to be invoked more than once in the same AppDomain, contrary to the behaviour he was experiencing.<br /><br />I consulted MSDN, and found the following definitions:<br />Static Classes [C#]<br />"<i>Static class members can be used to separate data and behavior that is independent of any object identity...</i>"<br />"<i>Static classes are loaded automatically by the .NET Framework common language runtime (CLR) when the program or namespace containing the class is loaded.</i>"<br /><br />Static Constructors<br />"<i>A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced.</i>"<br /><br />My colleague was working with .Net 3.0 using a class that derived from ClientBase<T> in the System.ServiceModel namespace.<br />Basically, he added a static constructor to define a single EndPoint for all the instances of this derived ClientBase(T).<br /><br />Upon further inspection, we saw that what was actually happening was that the Assembly containing the derived class was being loaded and instantiated by WCF using Reflection.<br /><br />With this in mind, I decided to go back to basics and create a simple program to see whether there was a difference in the behaviour of static classes and static constructors when working with an Assembly loaded using Reflection.<br /><br />I created a new C# solution that contained a Console Application called Demo and a Class Library called ReflectedAssembly.<br /><br />1. Demo<br />In Demo, I added a static class called MyStaticClass.<br />To this class I added a static constructor and a public static method called Call which had a string parameter.<br />When Call is invoked, it will write the string parameter to the Console.<br />In the static constructor, I added a call to the Call method, passing "cctor" as a parameter.<br /><br />2. ReflectedAssembly<br />I added a reference from ReflectedAssembly to Demo.<br />I added a class named ReflectedClass and a single method named DoIt which accepted a string as a parameter.<br />In the DoIt method, I added a call to MyStaticClass.Call, passing the string parameter.<br /><br />3. Demo<br />Back in Demo, I wrote the following in the program Main:<br />---<br /><font face="Courier New">Assembly TheAssembly;<br />Type TheType;<br /><br />MyStaticClass.Call("main start");<br /><br />TheAssembly = Assembly.LoadFile("**PATH**");<br />TheType = TheAssembly.GetType("ReflectedClass");<br /><br />if (TheType != null)<br /> TheType.GetMethod("DoIt").Invoke(Activator.CreateInstance(TheType), new object[] { "hello" });<br /><br />MyStaticClass.Call("main end");</font><br />---<br /><br />I added a breakpoint to the static constructor in MyStaticClass, but was disappointed to see it only get hit once. It seems I had not managed to reproduce the scenario that my colleague had experienced.<br /><br />I spent some time trying to figure out precisely what would cause the static class to be constructed mulitple times.<br />In the end I discovered that it could be achieved in the following way:<br />1. In the program code, making a copy of the ReflectedAssembly and Demo Assemblies in a different folder.<br />2. Using Assembly.LoadFrom to load the ReflectedAssembly Assembly as opposed to Assembly.LoadFile.<br /><br />Once my code was changed to use this method, I found that my static constructor was being invoked twice.<br /><br />Next, I wanted to find out why this was happening.<br />I added some additional code to the Call method in MyStaticClass, such that the following information was also written out to the Console:<br /><UL><LI>The process ID</LI><br /><LI>The managed thread ID</LI><br /><LI>The AppDomain ID</LI><br /><LI>The handle of the current Call method</LI></UL><br />I was hoping to see that somewhere, one of these values would be different.<br />My initial concern was that there may be some kind of context based issue around multi-threading.<br /><br />After running the program again, I discovered that the process, thread and AppDomain IDs were all the same.<br />The difference was in the MethodHandle for the Call method.<br />In the two calls from the program Main (where "main start" and "main end" were written), the handle is the same, but in the call from ReflectedClass, the handle was different.<br />This seems to indicate that the instance of MyStaticClass that is used by ReflectedClass differs from the instance used by the program Main, which would explain why the static constructor was being called twice.<br /><br />By enumerating the Assemblies of the current AppDomain, I can see that there are actualy two copies of my Demo Assembly in memory.<br />It appears that each contains an instance of the static class MyStaticClass, and this is why the static constructor has been invoked twice.<br />It is interesting to note that if I use Assembly.LoadFile to load ReflectedAssembly, there will also be two copies of the Assembly in memory, but the reference to the Assembly has been resolved to the same instance as my program Main is running.<br />However, if I use Assembly.LoadFrom, there seems to be an issue with resolving the reference to the existing Assembly and the reference is resolved to the new Assembly in memory instead.<br /><br />I decided to take my work a little further and see if I could produce multiple instances of the static class in memory.<br />I modified my program so that it loads the ReflectedAssembly Assembly three times, from a different location each time.<br />If I use Assembly.LoadFile, although the Assembly is actually loaded into memory an additional three times, the reference to Demo is always resolved to the first copy in memory, the static constructor only runs once, and the calls to the MyStaticClass.Call method are on the same instance of the static class.<br />However, using Assembly.LoadFrom (with the Assemblies in a different location each time) causes the same behaviour as before - this time the static constructor is invoked 4 times, and the calls to MyStaticClass.Call are on different instances of the static class.<br /><br />I refer to the MSDN entry for the Assembly.LoadFrom method:<br />"<i>If an assembly with the same identity is already loaded, LoadFrom returns the loaded assembly even if a different path was specified.</i>"<br />This does not appear to be true. The code I ran above demonstrates that actually, LoadFrom is returning the newly loaded Assembly each time, and that the Assembly references are being resolved to newly loaded Assemblies too.<br /><br /><u>Demo Program</u><br />A demo program that shows this in detail can be downloaded <a href="http://www.memia.biz/blogs/c2o/SctDemo.zip">here</a>.<br />You are welcome to the source code, which is written in C# 2.0. Please contact me if you would like it.<br /><br /><u>Conclusion</u><br />Static classes and static constructors may only static in the context of the loaded Assembly.<br />If using Reflection to load Assemblies, you may unknowingly end up with multiple instances of your static classes contrary to accepted wisdom.<br />Essentially, you cannot rely on there being a single instance of a static class in your AppDomain.<br /><br />In addition, using Assembly.LoadFrom does not guarantee that any Assemblies you are loading are resolved to in-memory copies, despite what is asserted in MSDN.<br />This is particularly important because this is what it appears is happening when using WCF in .Net 3.0.<br /><br />None of this necessarily poses a problem however: as long as we are aware that this is the case we can work with it.Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2220911881289577106.post-32704691016360088252007-12-02T19:13:00.000+00:002007-12-02T19:19:17.514+00:00Private Invoking Using ReflectionWhilst working on a product the other day, a thought occured to me with regard to Reflection in Microsoft.Net.<br />I wondered whether it would be possible to create an instance of a type with Internal or Private scope which was located in another assembly.<br /><br />As I understand it:<br /><UL><LI>An object declared with Internal scope should only be visible inside the assembly in which it is located.</LI><br /><LI>An object with Private scope should only be visible to the object that contains it. Private objects can not be declared at namespace level, only within other objects.</LI></UL>To see whether it was possible, I created a test.<br />I created a Class Library, FormLib, which contained a Public class name FormWrapper.<br />FormWrapper contains three further classes: PublicForm, InternalForm and PrivateForm.<br /><br />PublicForm is declared as a Public class with a Public constructor.<br />InternalForm is declared as an Internal class with an Internal constructor.<br />PrivateForm is declared as a Private class with a Private constructor.<br />All three classes inherit from Form and contain a single Label control that states "This is a ... form", with "..." replaced by the scope of the class.<br /><br />I then created a Windows Forms project called Demo which contained a Form. Demo is the startup project.<br />In Demo, I added three buttons, which would attempt to create an instance of PublicForm, InternalForm and PrivateForm respecitvely.<br /><br />To start, I needed to obtain the Assembly object representing FormLib. This was relatively easy and was achieved by referencing FormLib from my Demo project and then enumerating the Assembly objects contained in the current AppDomain:<br />---<br /><font face="Courier New">...<br />Assembly _Target;<br /><br />foreach (Assembly Item in AppDomain.CurrentDomain.GetAssemblies())<br />{<br /> if (Item.FullName.StartsWith("FormLib"))<br /> {<br /> _Target = Item;<br /> break;<br /> }<br />}<br />...</font><br />---<br /><br />I assumed creating an instance of the Public class would be easiest, so I implemented this first.<br />The Assembly object has a method CreateInstance, which can be used to generate an instance of a type, as so:<br />---<br /><font face="Courier New">...<br />object TheObject;<br /><br />TheObject = _Target.CreateInstance("FormLib.FormWrapper+PublicForm", false, BindingFlags.Public | BindingFlags.Instance, null, null, null, null);<br />...</font><br />---<br /><br />The first parameter of CreateInstance is the full name of the type I want to create.<br />"FormWrapper+PublicForm" indicates that the type PublicForm is inside the type FormWrapper, which is unlike the standard syntax for a type inside a namespace, which would simply be "Namespace.Type".<br />The third paremeter, which is a BindingFlags enumeration, indicates:<br /><UL><LI>Public - The public declarations of the type should be searched</LI><br /><LI>Instance - An instance should be created</LI></UL>The way that CreateInstance actually works is to generate the Type specified in the first parameter ("FormLib.FormWrapper+PublicForm" in this case) and then using the static CreateInstance method of the Activator object to actually generate the instance. This in turn uses RuntimeType.CreateInstanceImpl (RuntimeType is Internal to System) which actually invokes the constructor of the Type.<br />We could, of course, use Activator directly, but we would be unable to do this with Internal and Private types in a different Assembly because the types are not available to us directly.<br /><br />Now if the above code works, I want to actually display the form I have just created. To achieve this, following the above code I carry out the following:<br />---<br /><font face="Courier New">...<br />if (TheObject is Form)<br />{<br /> Form TheForm;<br /><br /> TheForm = (Form)TheObject;<br /> TheForm.ShowDialog();<br />}<br />...</font><br />---<br /><br />I ran my code to see what happened, and PublicForm was shown as expected.<br /><br />Moving on, I decided to try and repeat the above with the Internal and Private classes.<br />To achieve this, I made a small modification to the call to CreateInstance, first to create the types of the InternalForm and PrivateForm types, and second to change the BindingFlags to Private instead of Public:<br />---<br /><font face="Courier New">...<br />TheObject = _Target.CreateInstance("FormLib.FormWrapper+InternalForm", false, BindingFlags.Private | BindingFlags.Instance, null, null, null, null);<br />...<br />TheObject = _Target.CreateInstance("FormLib.FormWrapper+PrivateForm", false, BindingFlags.Private | BindingFlags.Instance, null, null, null, null);<br />...</font><br />---<br /><br />Upon executing the code, in both cases the form was shown as expected.<br />To provide further proof that internal or private methods could be executed using reflection, I decided to add a method named "AMethod" to each of the classes.<br />The scope of the method was the same as the class itself, so there was a Public, Internal and Private method.<br />In each method, a messagebox will be shown displaying that the method had been invoked.<br /><br />Directly following the line "TheForm.ShowDialog();" in each case I added the following code to attempt to invoke the method:<br />---<br /><font face="Courier New">...<br />foreach (MethodBase Item in TheObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Private | BindingFlags.Instance)<br />{<br /> Item.Invoke(TheObject, null);<br /> break;<br />}<br />...</font><br />---<br /><br />The objective of the above code is to enumerate all of the publically and privately available methods in the type represented by TheObject.<br />This reveals the "AMethod" method (which is of type MethodBase), which I can then invoke by calling Invoke and passing the instance of the type in as a parameter.<br />The second parameter for Invoke is the parameters for the method call (which can be passed as an array of objects - "object[]"). In this case, the method has no parameters so I simply pass in null.<br /><br />The method could also be invoked by using the InvokeMember method of the Type. However, I found this unsuccessful with methods with Private access so I discounted it.<br /><br /><B>A Potential Solution</B><br />A method that you could use to add some protection to your internal or private code is to monitor the stack trace when your method is invoked. You could also do this upon object construction by adding a monitor to your class constructors.<br />Basically, you can retrieve a list of the current call stack at the start of each method and ensure that the call to your method came from within your own class or within your own assembly, depending on whether it is a private or internal method respectively.<br />The following code demonstrates the use of this to ensure the caller is in the current assembly, which will validate access to an internal method:<br />---<br /><font face="Courier New">...<br />StackTrace Trace = new StackTrace();<br />if (Trace.FrameCount > 2)<br /> if (Trace.GetFrame(1).GetType().Assembly != Assembly.GetExecutingAssembly())<br /> throw new Exception("The call to this method is invalid");<br />...</font><br />---<br /><br />This works by examining the second method on the call stack (frame 1), which will be the direct caller of the current method on the call stack (frame 0). If the caller is not in the same assembly as the current frame then you know that it is in another assembly and has not been made internally.<br /><br />This works a treat but sadly adds complexity to your program and slows it down. However, if you are producing code that must only be executed internally or privately, this method may offer a reasonable way of protecting it.<br /><br /><B>Conclusion</B><br />You may create classes for internal use only in your assembly, which have internal or private members, properties or methods, but you cannot rely on the fact that these classes and members will not be created and consumed outside of your own code.<br />The power of .Net Reflection demands that you must not consider your internal and private code to be internal or private.<br /><br />If you would like the demo program I produced to show this working, it is available <a href="http://www.memia.biz/blogs/c2o/PrivateInvoke.zip">here</a>.<br /><br />Until next time!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-25581999666284022522007-11-18T15:58:00.000+00:002007-11-20T08:36:02.084+00:00Comparing ISINST to CASTCLASSI was reading through a corporate C# coding standard the other day for one of my clients, and noticed that one of the coding requirements in the standard related to casting of types in code.<br />Their standard stated that all type conversions in C# should be accomplished by using the 'as' keyword rather than using a direct cast (i.e. '(type)').<br />I quizzed my client on this to see what formed the basis of their choice to use 'as'. They had no explanation, but said that they felt it could be faster.<br /><br />Following on from this, I was interested to see whether using 'as' or '(type)' was faster for type conversion.<br /><br />In .Net IL, 'as' is compiled to 'isinst'. isinst performs a type conversion and returns null if the specified type conversion is not valid.<br />This differs from using '(type)', which compiles to 'castclass'. castclass also performs a type conversion but throws an Exception if the specified type conversion is not valid.<br />This is an important difference. For example, consider the following example using 'as' (isinst):<br /><font face="Courier New">void Foo1(object ObjA)<br />{<br /> ClassDef ObjB;<br /><br /> ObjB = ObjA as ClassDef;<br /> ObjB.Property = "12345";<br />}</font><br /><br />In the example, we have to be certain that we know ObjA can be converted to the ClassDef type, ObjB, because if it cannot, a NullReferenceException will occur in the line where the property is set.<br />A better implementation of the above example could be:<br /><font face="Courier New">void Foo2(object ObjA)<br />{<br /> ClassDef ObjB;<br /><br /> ObjB = ObjA as ClassDef;<br /> if (ObjB != null)<br /> ObjB.Property = "12345";<br />}</font><br /><br />If we consider the same example using '(type)' (castclass):<br /><font face="Courier New">void Foo3(object ObjA)<br />{<br /> ClassDef ObjB;<br /><br /> ObjB = (ClassDef)ObjA;<br /> ObjB.Property = "12345";<br />}</font><br /><br />Again in this example we have to be sure that the conversion between the two types is valid, because else a TypeConversionException will occur on the line where ObjA is cast to ClassDef.<br />There could be two potential alternatives to the castclass example:<br /><font face="Courier New">void Foo4(object ObjA)<br />{<br /> try<br /> {<br /> ClassDef ObjB;<br /><br /> ObjB = (ClassDef)ObjA;<br /> ObjB.Property = "12345";<br /> }<br /> catch (Exception ex)<br /> {<br /> // Do something useful<br /> throw ex;<br /> }<br />}</font><br /><font face="Courier New">void Foo5(object ObjA)<br />{<br /> ClassDef ObjB;<br /><br /> if (ObjA is ClassDef)<br /> {<br /> ObjB = (ClassDef)ObjA;<br /> ObjB.Property = "12345";<br /> }<br />}</font><br /><br />In the examples above, Foo1 and Foo3 would be appropriate to use if we knew that the object ObjA can definitely be converted to ClassDef. However, this may not always be likely, particularly in these examples becuase the parameter ObjA is an object type.<br />In these circumstances, it could be more appropriate to use Foo2, Foo4 or Foo5, because they offer security against failures during the conversion process.<br />In Foo2, we rely on isinst returning null if the conversion is not valid, and so we check for null after the conversion.<br />In Foo4, we handle an exception that could be raised during a failed castclass.<br />In Foo5, we first check to see whether ObjA is a ClassDef (using isinst - 'ObjA is ClassDef') and then perform the conversion in the knowledge that it will not cause an exception.<br /><br />Now I had five potential examples for performing a type convesion, I thought it would be interesting to see whether there was a great deal of difference in the time taken to carry out the different examples.<br />I wrote a test project which used a high-precision StopWatch to time each of the procedures.<br />I timed each procedure as it performed one billion casts, repeated over 50 iterations to ensure that a good average time could be ascertained.<br />Following on from this I analysed the results to see which of the above five examples was fastest.<br /><br />The total time for all 50 billion conversions for each test were:<br />Foo1 = 1,466,176 ms<br />Foo2 = 1,506,633 ms<br />Foo3 = 1,499,661 ms<br />Foo4 = 1,519,072 ms<br />Foo5 = 1,689,141 ms<br /><br />And the average times per iteration (1 billion conversions) were:<br />Foo1 = 29,323.52 ms<br />Foo2 = 30,132.66 ms<br />Foo3 = 29,993.22 ms<br />Foo4 = 30,381.44 ms<br />Foo5 = 33,782.82 ms<br /><br />Foo1 was the fastest, closely followed by Foo3 (which was around 2.284% slower).<br />However, as neither Foo1 or Foo3 contain any checks to ensure that the conversion was a success so they may be unsuitable for general use.<br /><br />Of the remaining methods, Foo2 was fastest, which involved checking for a null value after using isinst, followed by Foo4 (the the try...catch block around castclass) and finally Foo5, which was a combination of isinst and castclass. Foo5 was significantly slower than all the other methods, being around 3.5 seconds\million conversions slower than the slowest of the other four methods.<br />In order to directly compare isinst and castclass, we can examine Foo1 and Foo3. Consider the IL for Foo1 and Foo3 respectively:<br />Foo1<br /><font face="Courier New">...<br />IL_0014 ldloc.2<br />IL_0015 isinst TestCastStyle.ClassDef<br />IL_001a stloc.1<br />IL_001b ldloc.1<br />IL_001c ldstr "12345"<br />IL_0021 callvirt instance void TestCastStyle.ClassDef::set_Property(string)<br />...</font><br /><br />Foo3<br /><font face="Courier New">...<br />IL_0014 ldloc.2<br />IL_0015 castclass TestCastStyle.ClassDef<br />IL_001a stloc.1<br />IL_001b ldloc.1<br />IL_001c ldstr "12345"<br />IL_0021 callvirt instance void TestCastStyle.ClassDef::set_Property(string)<br />...</font><br /><br />The code for the methods is identical, other than IL_0015, which uses isinst in Foo1 and castclass in Foo3.<br /><br />In the tests I ran, Foo1 took around 29.32ms\million conversions whereas Foo3 took 29.99ms\million, which is a difference of 0.67ms\million.<br />This confirms that using isinst is definitely quicker than castclass.<br /><br />Considering the scenario where a check must be performed to ensure the conversion is valid, we can compare Foo2 (isinst) to Foo4 or Foo5 (castclass). The IL for these methods is:<br />Foo2<br /><font face="Courier New">...<br />IL_0014 ldloc.2<br />IL_0015 isinst TestCastStyle.ClassDef<br />IL_001a stloc.1<br />IL_001b ldloc.1<br />IL_001c brfalse.s IL_0029<br />IL_001e ldloc.1<br />IL_001f ldstr "12345"<br />IL_0024 callvirt instance void TestCastStyle.ClassDef::set_Property(string)<br />...</font><br /><br />Foo4<br /><font face="Courier New">...<br />try<br />{<br /> IL_0014 ldloc.2<br /> IL_0015 castclass TestCastStyle.ClassDef<br /> IL_001a stloc.1<br /> IL_001b ldloc.1<br /> IL_001c ldstr "12345"<br /> IL_0021 callvirt instance void TestCastStyle.ClassDef::set_Property(string)<br /> IL_0026 leave.s IL_002b<br />}<br />catch [mscorlib]System.Exception<br />{<br /> IL_0028 pop<br /> IL_0029 rethrow<br />}<br />...</font><br /><br />Foo5<br /><font face="Courier New">...<br />IL_0014 ldloc.2<br />IL_0015 isinst TestCastStyle.ClassDef<br />IL_001a brfalse.s IL_002e<br />IL_001c ldloc.2<br />IL_001d castclass TestCastStyle.ClassDef<br />IL_0022 stloc.1<br />IL_0023 ldloc.1<br />IL_0024 ldstr "12345"<br />IL_0029 callvirt instance void TestCastStyle.ClassDef::set_Property(string)<br />...</font><br /><br />At first glance, I had assumed that Foo4 would be slowest of these methods, but the results were:<br /><UL><LI>Foo2 took 30.13ms\million conversions</LI><br /><LI>Foo4 took 30.38ms\million conversions</LI><br /><LI>Foo5 took 33.78ms\million conversions</LI></UL><br /><br />I was surprised to see that Foo5 was by far the slowest. There does not seem to be a massive difference between Foo2 and Foo4 under the test conditions, but if an Exception was raised at IL_0015 in Foo4, this would slow the method down considerably, whereas Foo2 would continue to be very quick.<br /><br />The conclusions from the tests I performed are:<br /><UL><LI>In a direct comparison, isinst is quicker than castclass (although on slightly)</LI><br /><LI>When having to perform checks to ensure the conversion was successful, isinst was significantly quicker than castclass</LI><br /><LI>A combination of isinst and castclass should not be used as this was far slower than the quickest "safe" conversion (over 12% slower)</LI></UL><br /><br />If you would like to run the tests yourself, drop me an <a href="mailto:blogs.c2o@memia.biz">e-mail</a> and I will send you the test program I used. Additionally, if you would like the analysis files containing the timings and code dumps, I can also send you this.<br /><br />Have fun!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-79230808906613188062007-11-02T21:30:00.000+00:002007-11-02T21:38:18.960+00:00Using Win32 to Manipulate the UIWhilst working on an application at a client's site the other day, I noticed that access to certain code was being controlled by disabling buttons on a form.<br />The code in question should not be invoked under certain conditions (in this case, under certain security conditions), and so the application developers had assumed that disabling the button that invoked the code would prevent the user from invoking the functionality behind the button.<br /><br />Sadly, this is not the case.<br />I demonstrated a very simple attack using Win32 API calls that enabled the button, and allowed the user to click on it, whether or not the application had disabled it or not.<br /><br />In this article, I will be discussing the technique I used, and how you can write code that is protected from this kind of attack.<br /><br />To demonstrate the attack to my client, I implemented my code in Microsoft Excel. I did this because most desktop PCs tend to have Microsoft Excel and I wanted to show my client that you do not need development tools like Visual Studio in order to orchestrate a simple attack like this.<br />In addition, I used a standard network user account to to show that this attack can be performed by a standard user, with the only requirement (in this scenario) being access to VBA in an Office product and the ability to execute macros in the product.<br /><br />In order to enable the disabled button, the user will need to carry out the following actions:<br />- Find the window handle (HWND) of the button<br />- Enable the button<br /><br />To start new Microsoft Excel workbook should be created, and the Visual Basic Editor (Tools -> Macros -> Visual Basic Editor) should be open.<br />A new Module must be added to the current workbook. The following code must go into the Module - it will not work unless it is in a VBA code Module (not WorkSheet or WorkBook code).<br /><br /><u>Find the HWND</u><br />In order to enable the button, the user needs to know the window handle (which is often referred to as the HWND) of the button.<br />If the user can use a tool such as Spy++ this is very easy, but as most users will not have it we need a way of discovering the window handle from Excel.<br /><br />An easy way to do this is to produce a list of window handles that exist in the current session.<br />This is done by making an API call to EnumWindows (which lives in user32).<br />EnumWindows requires a callback to enumerate the window list, which is simple to achieve in Excel; We simply declare a method that matches the callback specification:<br />---<br />Private Function EnumWindowsProc(ByVal hwnd As Long, ByVal lparam As Long) As Long<br />---<br /><br />This method matches the requirement, so we can now make the API call as required. To do this, we need to make the API method declaration and call it:<br />---<br />' This is the API method declaration<br />Private Declare Function EnumWindows Lib "user32" (ByVal callback As Long, ByVal lparam As Long) As Boolean<br /><br />' This method, when invoked, will make the API call<br />Public Sub EnumerateAllWindows()<br /> EnumWindows AddressOf EnumWindowsProc, 0<br />End Sub<br />---<br /><br />When the EnumerateAllWindows method is invoked, the API call is made to EnumWindows, and our callback method (EnumWindowsProc) will be invoked.<br /><br />In EnumWindowsProc, we get passed a window handle in hwnd. The lparam parameter serves no purpose in this example and can be ignored (it will be 0).<br />The value in hwnd will be the first enumerated window handle. To get the next one, the EnumWindowsProc must return a true value:<br />---<br />Private Function EnumWindowsProc(ByVal hwnd As Long, ByVal lparam As Long) As Long<br /> Debug.Print hwnd<br /> EnumWindowsProc = 1<br />End Function<br />---<br /><br />This will then be repeatedly invoked until all the window have been enumerated, and the Immediate window will now contain a list of a couple of hundred numbers.<br /><br />However, this is not very useful as far as the user is concerned, because they do not know which of these window handles are any use to them.<br />To help the user, the name of the window whose handle has been displayed can also be obtained.<br />To do this, an API call to GetWindowTextA (which also lives in user32) can be made, which has the following API method declaration:<br />---<br />Private Declare Function GetWindowTextA Lib "user32" (ByVal hwnd As Long, ByVal Text As String, ByVal maxcount As Long) As Long<br />---<br /><br />And now in EnumWindowsProc, the following code is added before the Debug.Print statement:<br />---<br /> Dim Length As Long<br /> Dim Text As String<br /><br /> ' Empty string to accept a name<br /> Text = String(100, " ")<br /><br /> ' Get the text<br /> Length = GetWindowTextA(hwnd, Text, 100)<br /> If Length > 0 Then<br /> Text = Mid$(Text, 1, Length)<br /> Else<br /> Text = ""<br /> End If<br /><br /> Debug.Print Text<br />---<br /><br />There are some important points to note when using GetWindowTextA:<br />- A string (named Text) of length 100, containing spaces, was created for the string to be put into. This must be done, else the string will always be empty.<br />- The resulting string (from GetWindowTextA) was terminated using the length returned. If this was not done the Text would contain a string terminator (null, '\0') and then spaces up to the 100th character and would be unusable.<br /><br />After including the above code, invoking the method will dump the name of the window and the window handle to the immediate window.<br /><br />As event this output is not ideal, Excel can be used to dump the list to the current Sheet. A member variable, RowCounter, of type Integer is added to the Module, and then in EnumerateChildWindows method, is set this value to 1.<br />Now in EnumWindowsProc, the Debug.Print statements are changed to:<br />---<br /> Application.ActiveSheet.Cells(RowCounter, 1).Value = Str(hwnd)<br /> Application.ActiveSheet.Cells(RowCounter, 2).Value = Text<br /><br /> RowCounter = RowCounter + 1<br />---<br /><br />When this code is now invoked, it dumps a list of window handles and window names to the current spreadsheet - much more useful when looking for something.<br /><br />Now that is done, a list of the window handles in the system can be obtained. This can be tested by running Calc (calc.exe) and then invoking EnumerateAllWindows. The text "Calculator" will be visible next to a window handle on the list somewhere.<br /><br />That's a good start, but if the user is trying to enable a button on a form, at the moment they will only have visiblity of the form's window handle.<br /><br />To have a look at what is on the form, another API call, EnumChildWindows. EnumChildWindows will be used to enumerate all the child windows of a specified window handle.<br />Each button (and indeed most forms components) will have their own window handle.<br />The declaration for EnumChildWindows is:<br />---<br />Private Declare Function EnumChildWindows Lib "user32" (ByVal hwndParent As Long, ByVal callback As Long, ByVal lparam As Long) As Boolean<br />---<br /><br />In the declaration hwndParent refers to the parent window handle, and then the callback and lparam parameters are the same as before.<br />To use EnumChildWindows, another callback method is required, which is declared in the same was as with EnumWindowsProc:<br />---<br />Private Function EnumChildWindowsProc(ByVal hwnd As Long, ByVal lparam As Long) As Long<br />---<br /><br />The method body is the same as EnumWindowsProc, so it will also produce a list of window handles and associated text.<br /><br />A method called EnumerateChildWindows is declared, which will read the number (window handle) in the currently selected cell and enumerate child windows of it:<br />---<br />Public Sub EnumerateChildWindows()<br /> If IsNumeric(Application.Selection) Then<br /> Dim Number As Long<br /><br /> Number = Application.Selection<br /> If Number > 0 Then<br /> Application.ActiveSheet.Cells.Clear<br /> RowCounter = 1<br /> EnumChildWindows Number, AddressOf EnumChildWindowsProc, 0<br /> End If<br /> End If<br />End Sub<br />---<br /><br />If the user clicks on a window handle in the worksheet and then runs the method EnumerateChildWindows, the current list will be cleared and then the child windows of the selected window handle will be displayed.<br /><br />This can be repeated if necessary to pass through multiple layers of child windows, but it is most likely that the button the user is looking for has been found the first time EnumerateChildWindows is invoked.<br /><br />This can be tested this by:<br />- Run Calc (calc.exe)<br />- Invoking EnumerateAllWindows<br />- Selecting the window handle next to "Calculator" in the list<br />- Invoking EnumerateChildWindows<br />A list that contains all of the controls on the Calculator form should now be displayed.<br /><br />The user will now be able to obtain the window handle of the button they wish to enable.<br /><br /><br /><U>Enable The Button</U><br />In the above section, the user can obtained the window handle for a control that they wish to enable.<br /><br />Now the user needs to enable the button.<br />This is achieved by making an API call to EnableWindow, which is declared in user32:<br />---<br />Private Declare Function EnableWindow Lib "user32" (ByVal hwnd As Long, ByVal state As Boolean) As Boolean<br />---<br /><br />When making the API call, the window handle must be supplied in hwnd, and the enabled state of the target window in state.<br />A method can be declared to do this:<br />---<br />Public Sub EnableSelectedWindow()<br /> If IsNumeric(Application.Selection) Then<br /> Dim Number As Long<br /><br /> Number = Application.Selection<br /> If Number > 0 Then<br /> EnableWindow Number, True<br /> End If<br /> End If<br />End Sub<br />---<br /><br />Now, the user can simply select a window handle in the list in the spreadsheet and invoke EnableSelectedWindow, and the window will become enabled.<br /><br />This can be tested by:<br />- Run Calc (calc.exe)<br />- Putting Calc into Scientific mode (View -> Scientific). Note that the Ave, Sum, s, Dat, A, B, C, D, E and F buttons are disabled<br />- Invoking EnumerateAllWindows<br />- Selecting the window handle next to "Calculator" in the list<br />- Invoking EnumerateChildWindows<br />- Select the window handle next to one of the disabled button names (i.e. "Ave") - Invoking EnableSelectedWindow<br /><br />The button will now be enabled. This can repeated as many times as necessary with other controls on the form.<br /><br />This method will work on anything that has a window handle in Win32.<br /><br /><U>Conclusion</U><br />It is very easy to modify the state of controls using Win32.<br />This is because almost all standard controls in Windows have a window handle. This is a fundamental part of the operation of Microsoft Windows, and cannot be prevented.<br /><br />It is important when designing and developing UI-invoked code that preventative steps are always taken to double-check that code execution is permitted.<br />As this article has demonstrated, it cannot be assumed that code is protected by simply disabling or hiding UI components.<br />A much more secure method would be to disable a control but to verify that execution is permitted inside the control's Click event or inside the code that is being executed.<br /><br />Additionally, it is important to realise that it is not only the Enabled state of controls that can be influenced. In fact, using the same principal described in this article a user can change any of the following aspects of a window:<br />- Colour<br />- Position<br />- Size<br />- Visibility<br /><br />Following the demonstration of the above to my client, they readily agreed that a better approach to protecting code from unwanted execution was required, and they have taken steps to prevent code access in this way.<br /><br />If you would like to download a copy of the code used in this article, it can be downloaded <a href="http://www.memia.biz/blogs/c2o/win32_code.zip">here</a>. This code is written (as per this article) for use in Microsoft Excel but can easily be changed to work with other Office products.<br /><br />Have fun!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-41572047521570457482007-09-10T17:15:00.000+01:002007-09-10T17:29:12.780+01:00Trial Game UnlockingThe other day, I downloaded a trial version of a game from a website.<br />The game was a fairly simple one where you have a series of balls rolling along a track, and you have to shoot coloured balls at them to cause them to pop.<br /><br />I was enjoying the game a lot - it was great fun - but then after 60 minutes the game turned itself off and displayed a message stating that my trial was over and that I would have to purchase the game to continue playing.<br />A lot of software these days is based on trial use systems, whereby the user is entitled to a certain amount of use of the program, and then after a this time has been used the program locks itself so that it can no longer function, or functions with severely reduced functionality.<br /><br />The problem with this method of software protection though, is that the actual program is still on the user's PC - after the trial period the software "locks" but is actually still fully available.<br /><br />With this in mind, I decided to have some fun seeing how easy it would be to simply bypass the trial protection and to continue playing the game.<br />Before I continue, I would like to say that I do believe people should pay a fair price for software, as I myself am aware of how much effort goes into producing applications and games, and that I did actually purchased the software in question.<br /><br />To start, I installed the software on a new PC, thereby unlocking it for full use.<br />I then ran the software.<br />The first thing that happened was that a nag screen appeared which informed me that I had only 60 minutes of free gameplay left. I clicked on the Play button on this screen to start the game. The nag screen then disappeared and a couple of seconds later the game appeared on screen.<br /><br />I closed the program, and then opened OllyDBG. I opened the program in OllyDBG and selected Run. The nag screen appeared.<br />At this point I Paused OllyDBG and noticed I was in kernel32. I selected "Execute till user code".<br />I now noticed I was in a large proc that seemed to control the trial window that had been displayed.<br />As the trial window had been kind enough to inform me how much time was left in my trial period, I knew that this value had to have been supplied from somewhre, so I decided to have a look through the proc.<br />I saw something that interested me at +5FAD, which was the following:<br /><FONT face="Courier New"> PUSH 00533940 UNICODE "gTimeLeft"</FONT><br />Now time left could of course be for a number of different things, but it was a good place to start looking for what I was after. I set a breakpoint on this line and then let the program continue to run.<br />However, my breakpoint did not hit. So I tried a different method, I restarted the program, and then checked to ensure the breakpoint was still set on that line.<br />I then seleced Run.<br />A short while later, the breakpoint was hit - this was obviously used as part of the initialisation of the trial screen rather than during it's general running.<br /><br />The first thing I did now that the breakpoint had hit was to have a look at the new few lines of code:<br /><FONT FACE="Courier New">+5FAD PUSH 00533940 UNICODE "gTimeLeft"<br />+5FB2 LEA ECX, DWORD PTR SS:[EBP-2C]<br />+5FB5 CALL +87D3<br />+5FBA MOV DWORD PTR SS:[EBP-4], 1D<br />+5FC1 PUSH DWORD PTR DS:[5BA530]</FONT><br />I made the initial assumption that at +5FB5, there was a call to a proc that retrieved this value "gTimeLeft". I quickly stepped through the proc and resulting sub-proc calls to see whether I could find anything obvious, but couldn't.<br />I decided to get back to the main proc and step through this to see whether there was anything else helpful.<br />I stepped through until I got to +5FC1, where the value at 5BA530 was pushed onto the stack.<br />The value at this location turned out to be 0x3C (60), which was identical to the 60 minutes displayed on the trail screen. However, this could be pure coincidence and I wanted to be sure.<br />I set a new breakpoint on this line and then let the program run. I played it for a couple of minutes and then closed it.<br />After OllyDBG had informed me that the process had terminated, I restarted and ran the program, and shortly afterwards my breakpoint was hit again. This time the value was 0x3A (58). I let the program run so that the trial screen would appear, and lo and behold the message displayed the fact that I had 58 minutes remaining in my trial.<br /><br />Armed with an apparent location for the amount of time left in the game, I restarted the program, and then decided to perform an analysis on any code which accessed this memory location (5BA530).<br />In OllyDBG, I examined the location in memory and then used "Find References" to enumerate all the places where this memory location was referenced.<br />It turned out that there were 4 locations:<br /><FONT FACE="Courier New">+37B4 MOV DWORD PTR DS:[5BA530], EAX<br />+5FC1 PUSH DWORD PTR DS:[5BA530]<br />+6391 CMP DWORD PTR DS:[5BA530], EBC<br />+68DC PUSH DWORD PTR DS:[5BA530]</FONT><br />The most sensible way to proceed was to set a breakpoint on each of them, which I then did, and I then restarted and ran the program again.<br /><br />The first breakpoint that was hit was at +37B4, which seemed to load the number of remaining minutes into the memory location. At this stage, I thought that a simple modification of this line would allow one to play indefinitely, but I wanted a slightly cleaner solution, so I continued execution.<br />The next breakpoint hit was at +5FC1, which is where the value seemed to be loaded for display on the trial screen. I again continued execution. The trial screen was displayed, so I clicked on the Play button to load the game itself.<br />The next breakpoint to be hit was at +68DC. This was used to generate a debug message output using OutputDebugStringA in Kernel32. I removed this breakpoint (as it was hit every second) and again continued execution.<br />However, the final breakpoint was not hit, and so I decided to exit the game and see whether that may trigger anything, but it did not. The process terminated.<br /><br />So now I had a single point at which I could manipulate the game, +37B4, where the initial remaining time had been set. I restarted the program and ran it until this breakpoint was hit again.<br />I could easily of changed the remaining time value at this point, or simply modify the code so that instead of loading the remaining time into the address, it always loaded a high fixed value, but this didn't seem like a particularly elegant solution, so I wanted to actually find out where the trial screen was displayed so I could see whether there was a better way of influencing the program.<br />I stepped through the code until the proc returned (at +37C6). I stepped through the code here, and noticed that at +61FD, there was a call to +61BD, and that if I stepped over this, the trial screen was displayed and the game seemed to load. This is where I put my next breakpoint.<br />I restarted and ran the program, and then stepped into the proc that was called. I saw that the called proc only had a single call, so I stepped into this too.<br />Now I ended up in the large proc that contained the "gTimeLeft" line I found earlier, and a reference to the remaining time in 5BA530 (at +5FC1).<br /><br />I don't want to go through this large proc. A quick glance at it tells me that this is where the trial registration screen is displayed, and I want to intercept the execution before it gets here.<br />With this in mind, I go back to the original call into the large proc, and back to the original call into the calling proc, which is at +61FD.<br />There is a small proc here, which includes the line at +61E8:<br />+61E8 PUSH 00533970 ASCII "TrialScreen"<br />Now this is starting to look more interesting. This proc seems to be concerned with launching the trial screen. I would like to see where it is called from, so I examine the start of this proc, at +61D7 and see that there is a single call from +7FE3, which I go to.<br />I put a breakpoint on +7FE3, and then restart and run the program. The breakpoint hits straight away, so I decide to step over the line - I am not interested in how the trial screen is displayed at the moment - and see what happens.<br />As expected, the trial screen is displayed. I click the Play button and see that the trial screen closes, and immediately I am back into my code, at +7FE8. The line I just stepped over is just responsible for displaying the trial screen.<br />The line I am now on (at +7FE8) contains the a JMP to +81A6.<br />If I run the program now the game will load.<br />So, what will happen if I replace the CALL in +7FE8 with NOP instructions? Will the game load without a trial screen?<br />I decide to try it, and as I hoped, the trial screen is not displayed - the game just loads. I have managed to find where the trial screen is displayed from.<br /><br />I decide to have a look around to see what is going on with the code - I am particularly interested in the events leading up to the display of the trial screen.<br />I notice that there is a CMP at +7FD8 and a JNZ at +8FE1 just above the call to the trial screen. I set a breakpoint on these to see what is happening in them.<br />After restarting the program, I notice that the CMP is checking to see whether a value is 0 or not. If the value is 0, a JMP is made to the next line at +7FED, essentially this skips the trial screen.<br />I decide to force this jump by altering the Z flag. I then allow the program to run to see what has happened.<br />I actually end up being presented with a screen that tells me my trial period is over, and I can no longer play the game. I assume, from this, that this must be what gets called when there are no minutes left to use up and you cannot trial the game any more.<br />This isn't what I'm looking for though, so I have a look further up the proc to see what I can find. I notice that there is another CMP just above, at +7FC9. I put a breakpoint on this line, and notice that it has jumps from +7E9B and +7EB7.<br />I want to know whether either of these jumps are what leads to this instruction or whether the execution simply continues from the previous instruction (+7FC7) so I set a breakpoint on +7FC7.<br />I restart and run the code and see that the instruction +7FC9 is jumped to, because the breakpoint at +7FC7 is never triggered.<br />There is a JBE just after the CMP. This is always taken. If I force it not to be taken, I am presented with a screen asking for my order number for registration purposes. Again, not really what I am looking for.<br />So I decide to go back a bit further, to examine the jumps that led us to +7FC9, so I set breakpoints at +7E9B and +8EB7. Both jumps are actually JE instructions.<br /><br />I restart and run the program, and the breakpoint on +7E9B is triggered, but I notice the JE instruction at this address is not followed. I continue execution.<br />The breakpoint on +7EB7 is then triggered, and this time the JE is taken, so this is where the program execution branches to the whole registration screen\trial screen\end of trial screen area.<br /><br />Moving back down to look at the registration, trial and end of trial screen section in the proc, between +7FC7 and +7FF2, I notice that after each screen has been displayed (via a CALL), a JMP is made to +81A6.<br />Now this seems to be when the program is actually executed, so I go and examine the code located there.<br />Interestingly, the first things I notice are a ASCII reference to the program file, and a UNICODE reference containing the wors "Unable to extract game executable.".<br />This must be where the game is actually loaded from!<br />Now if the game is registered, then the entire section about registration screens and trial screens should be skipped, so I have a look and see if +81A6 is jumped to from anywhere else.<br />I can see the three jumps from the registration, trial and end of trial screens at +7FD6, +7FE8 and +7FF2, but there are also two additional jumps from +802D and +8049.<br />Both of these are located in some code that is just below the whole registration screen area, which starts at +7FF7.<br />I see that there are two jumps to +7FF7, one from +7E4F and one from +7E5B.<br />I go and have a look at these. They are both conditional JNZ based on CMP statements.<br />I set breakpoints, restart and run the code.<br /><br />The breakpoint at +7E4F is triggered (as expected; it is first). I quickly notice that neither this or the second JNZ are taken, and then the execution quickly proceeds to the registration screen.<br />I thought it may be prudent to force one of the JNZ, so I pick the first one at +7E4F and restart the program.<br />When the breakpoint is triggered, I simply change the Z register so the jump is taken, and run the program. None of the screens are displayed, and the game loads and plays successfully.<br /><br />I have found where I can bypass the registration and trial screens.<br />Simply changing the JNZ to a JMP (and filling the leftover byte with a NOP) will cause the program to execute every time, regardless of minutes remaining (0 or more). The software protection is, effectively, disabled.<br /><br />Just to see for myself, I wanted to modify the actual EXE file to see whether this change could easily be made permanent.<br />I open the EXE using UltraEdit and quickly see that the code is not encrypted. I modify the few bytes so that the JNZ is a JMP, and then save the file.<br />I can now run it every time without any prompting what-so-ever. I have even tried patching it after the trial period ran out (after 60 minutes was up) and it still works.<br /><br />This kind of technique of software protection is poor. It actually took me longer to write this article than it did for me to break the protection in this game.<br />The method used for this game relies on the fact that a wrapper has been produced around the game itself, and this wrapper provides all the registration and trial functionality. The actual game has no concept of this what-so-ever.<br />Also, the wrapper itself is poorly produced. The fact that I can bypass all the protection with a change to a single line of code is staggering. It would be better to have put a check into several places in the code, and also embedded further, regular checks into the game itself.<br />However, a lot of developers do not understand how vulnerable their code can be, particularly when they write their code in a language such as C++ and then compile it to assembler.<br />The actual assembler output from their C++ code may be very different from what they originally wrote, and could be susceptable to easy attack using methods like the ones I have used today.<br /><br />I am not going to produce a patch for this particular bit of software, because I am reluctant to give away the ability to bypass the software protection on what is actually a very good game. Like I said at the start of my article, I have actually purchased this game because I like it so much, and the only reason I have produced this article is because of my academic interest in the protection methods used in the real world.<br /><br />If you have any queries about this article, please do not hesitate to get in touch.<br /><br />Until next time...Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-89259476333328520112007-09-06T21:54:00.000+01:002007-09-06T21:56:50.359+01:00Good Password Generation?Following on from my previous articles about password generation and the potential flaws in using password generation tools, I thought it might be useful to produce a tool that generates robust passwords based upon a generation code (such as an asset number).<br /><br />I had the following objectives for the tool:<br /> - Generate passwords that were random every time<br /> - Generate a repeatable password based on a numeric seed using an algorithm that was not easy to break<br />I also wished for the generation to be configurable:<br /> - Allow passwords between 1 and 15 characters<br /> - Allow a character set to be specified<br /> - For random passwords, allow a quantity of passwords to be specified<br /> - For repeatable passwords, allow an asset number to be entered<br /><br /><u>RANDOM PASSWORD GENERATION</u><br />I started off by looking at producing passwords that were random every time. These would not be based on asset codes, but instead should generate passwords that appear truly random when compared to each other.<br /><br />I decided to implement two types of random password generator, both based on Microsoft .Net random number generators.<br />The first was to be based on the simple subtractive random number generator which is implemented by the .Net class Random.<br />The second would be based on the cyptographic random number generator, RNGCryptServiceProvider (in System.Security.Cryptography).<br /><br />To produce the passwords, the random number generator would be used to supply a byte array containing a sequence of character positions from the character set used to seed the passwords.<br /><br />For simplicity, say I was using the character set 'ABCDE' and I wanted a 8 character password.<br />I request a sequence of 8 bytes from the random number generator, each with a value between 0 and 4, and receive the byte array '0, 3, 2, 4, 4, 2, 0, 1'.<br />I then use these positions to retrieve characters from the character set, as so:<br />0 = A, 3 = D, 2 = C, 4 = E, 4 = E, 2 = C, 0 = A, 1 = B<br />Which gives a password 'ADCEECAB'.<br /><br />Passwords based on random number generators can be good because there should be no discernable pattern present in the generated sequence.<br /><br />However, passwords generated in this way do result in some security problems:<br /> - The passwords are not repeatable because they are not based on an asset number. This means they have to be stored somewhere for later retrieval, which may potentially represent a huge security risk.<br /> - The passwords may not be truly random. Random number generators work from a predefined formula for which gives the appearance of randomness, however, they are not truly random (see below for more on this).<br /><br />Before I move on, I would like to discusss the randomness of the passwords that can be generated using a random number generator.<br />A simple random number generator, such as the Random class in Microsoft.Net, is a pseudo-random number generator, that is, the numbers that are generated are not random at all, they are derived mathematically using a formula, and the numbers appear to be random.<br />The Random class (in .Net) uses a "seed" to generate a sequence of numbers. In .Net, by default this is based on the number of ticks so far in the day. However, a seed can also be supplied directly to the class Constructor.<br />This highlights an important limitation of simple random number generators - if the same seed is used again, the sequence of numbers generated will be the same.<br /><br />Create a simple program that instantiates a Random class with a seed of 1, and then gets the first 10 integers (Random.Next()).<br />Execute the program a few times. Each time the numbers generated will be the same, in the same order.<br />It is very important to accept that if the seed used to create the Random class can be ascertained, the entire sequence of numbers used to generate a password can be recreated, and this may prove the undoing of any password generator based on pseudo-random number generation.<br /><br /><u>REPEATABLE PASSWORD GENERATION</u><br />For a repeatable password to be generated, an asset code will be required. To simplify matters, the asset code will be limited to numerics only.<br /><br />I decided to implement two repeatable password generators:<br /> - Simple. This will be based on the principals outlined above with regards to using a fixed seed for random number generation. The seed will be the asset code.<br /> - Complex. This will be based on a method that uses a predefined formula to generate the asset code. I will not reveal the formula because I would like to see whether anyone can figure it out for themselves.<br /><br />To generate the actual passwords, the repeatable password generation will work in the same way as the random number generator, that is a sequence of valid numbers will be generated that will indicate the positions of the character to be used in the password from a character set.<br /><br />Repeatable password generators offer advantages over randomly generated passwords, because they do not need to be written down anywhere; They can be generated at any later time simply by supplying the asset code.<br /><br />However, they do have limitations:<br /> - The password that is generated is, ultimately, based on a formula of some sort and so can be broken given a large enough set to work with<br /> - The tool must be properly protected from unauthorised access. Access to the tool is, essentially, access to the entire system.<br /><br /><u>THE IMPLEMENTATION</u><br />I decided to implement each of the different generation methods (both random and repeatable) in classes that support a common interface, IRNG. This way my generation program does not care which actual implementation is being used to generate the passwords.<br /><br />I wrote a manager class called PwManager, which will be responsible for generating the passwords using the desired generator.<br /><br />I then placed the manager class, the interface and the generator classes in an assembly, and referenced this from my Windows Forms project.<br /><br />In my Windows Forms project, I added a form to allow the user to configure the generation method, password length and character set and also, depending upon the chosen generation method, the number of passwords to be generated or the asset code.<br />I then added a second form which would be used to display the results of the generation.<br /><br />When a button is pushed on the first form, the PwManager is instantiated and configured with the appropriate parameters, and the generation of the password(s) takes place. The resulting configuration information and password list is displayed on the second form.<br /><br /><u>DEMO PROGRAM</u><br />If you would like to download and use the password generator program, it can be downloaded <a href="http://www.memia.biz/blogs/c2o/PwGenerator.zip">here</a>.<br /><br />There are two assemblies in the download, a library and an executable. The executable is simply a UI which presents the functionality from the library.<br />Feel free to reference the library from your own code and make use of the generation methods.<br /><br />A final note: Please do not use the program to generate passwords for your organisation - it is freely available on the web (from my blog) and others could easily obtain it. Instead, the source code is (as always) available upon request - ask me for it and modify it to make it unique to your organisation.<br /><br /><u>CONCLUSION</u><br />I have demonstrated several techniques for generating passwords during this article.<br />I would be interested to hear if anyone can break the repeatable password generators, you are welcome to try!Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-2220911881289577106.post-40098901200196330722007-09-03T20:55:00.000+01:002007-09-03T21:01:02.122+01:00Bulk Password Generation Part 2In my previous article I managed to demonstrate that a password generation technique implemented by a tool in an organisation could be easily broken with as few as 300 passwords.<br />In the article I broke the password generator for the BIOS passwords generated by the aforementioned tool.<br />In this article, I will discuss breaking the local administrator passwords generated by the tool, and then go on to discuss the tool required to reproduce the passwords.<br /><br />It should be noted, before I continue, that I do not have the tool used to generate the passwords. Instead, I have been given a list of sequential passwords generated from the tool.<br />The tool itself generates passwords based on the asset tag of the PC they are for. The asset tags are a number.<br />The passwords I have been given are for the 500 assets numbered 0 - 499.<br /><br />Referring to my previous article, the local administrator passwords are 8 characters long, and were structured like this:<br /> UlUlUnns<br />Where U is Uppercase letter, l is lowercase letter, n is number and s was a symbol.<br /><br />In the same way as before, I started by looking at the first few passwords:<br />0 JcVvI32(<br />1 KdWwJ43)<br />2 LeXxK54*<br />3 MfYyL65+<br />4 NgZzM06-<br />5 OhAaN17!<br /><br />At this stage I began to get the same sinking feeling that I got when I worked on the BIOS passwords. The passwords are, again, sequential.<br />I briefly hoped that the producer of the password generator tool had the aptitude to at least use a different technique for the two different password types...<br />But fairly soon it became obvious that these passwords were as simple to break as the other ones.<br />In fact, using the same technique as demonstrated in my previous article, I broke the entire set of formulae for each letter in less than 20 minutes!<br />Although characters 2 and 4 of this password are lowercase, they are not mixed, so they are still as limited as the uppercase characters, i.e. 26 possibilities in the sequence.<br />The final formulae for each character turn out to be:<br /> 1) l = (n + 113) mod 137 mod 26<br /> 2) l = (n + 54) mod 153 mod 26<br /> 3) l = (n + 21) mod 113 mod 26<br /> 4) l = (n + 99) mod 117 mod 26<br /> 5) l = (n + 86) mod 193 mod 26<br /> 6) l = (n + 123) mod 127 mod 10<br /> 7) l = (n + 202) mod 239 mod 10<br /> 8) l = (n + 105) mod 129 mod 10<br /><br />Where l is the final number of the character in the sequence, and n is the asset number.<br />The character sequence for positions 1, 3 and 5 is A - Z (0 - 25).<br />The character sequence for positions 2 and 4 is a - z (0 - 25).<br />The character sequence for positions 6 and 7 is 0 - 9 (0 - 9).<br />The character sequence for position 8 is '!#$%&()*+-' ('0123456789').<br /><br />The only minor benefit that was present with these passwords is that a much larger sequence was needed in order to be sure of the generation techniques.<br />In fact, I needed the full 500 for character 7 and just under 400 for 3 of the others.<br /><br />That said though, the generation technique is still extremely poor, for the same reasons that the BIOS password generator was poor, and also:<br /><br />AS EASY TO BRUTE FORCE (Following on from previous article section)<br />The BIOS passwords could be relatively easily brute forced.<br />These passwords are as easy, despite the inclusion of the lowercase characters.<br />This is because, like the BIOS passwords, the entire sequence is strict in it's structure.<br />The lowercase characters are always at positions 2 and 4.<br />If, like with the BIOS passwords, the full character sequence could be used in each position (A-Z, a-z, 0-9, symbols) then there would be 72 possibilities at each position:<br /> 72^8 = 722,204,136,308,736<br />A whopping 722 trillion, over 60,784 times more than for the standard password, and still 36 times more than the strongest possible BIOS password (with 46 possibilities per position).<br /><br /><br />I had been asked if I could produce a tool that would reproduce the passwords, given the asset number.<br />I was now armed with the knowledge to do this, so I proceeded to produce a tool to do the work outlined in this and my previous article.<br /><br />I decided to write the tool in C# (Microsoft.Net 2.0).<br />A screenshot of the tool is shown below:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBEgNXsVDHQPRUMzW1-SRXCkauZEOiaCBAP8SdvEC-YWmXcfD63ZOnXypfTm10k0BjPZsDKa4VVL5_cWqUV3l3xOOxX0Z1tj4aEyCQZHa7WH5coCczHgPMuMui6OBR8GIiZbgvGivcPAU/s1600-h/CPGen_Screenshot.bmp"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBEgNXsVDHQPRUMzW1-SRXCkauZEOiaCBAP8SdvEC-YWmXcfD63ZOnXypfTm10k0BjPZsDKa4VVL5_cWqUV3l3xOOxX0Z1tj4aEyCQZHa7WH5coCczHgPMuMui6OBR8GIiZbgvGivcPAU/s400/CPGen_Screenshot.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5106069934584571026" /></a><br /><br />To use the tool, enter the asset code into the 'Asset Code' textbox, and click the Go button.<br />The Administrator password will appear in the "Admin Password" box and the BIOS password will appear in the "BIOS Password" box.<br />The tool itself simply implements the formulae described in this and my previous article to generate the passwords.<br />If you would like the source code for the tool, please e-mail me and I will send it to you.<br /><br />The tool can be downloaded <a href="http://www.memia.biz/blogs/c2o/CPGen.exe">here</a>.<br /><br /><br />To conclude:<br />Using password generation tools is a good idea. Company administrators find such tools invaluable in producing random passwords for hundreds, or thousands, of computers at an organisation.<br />Generation tools can produce passwords that appear to be significantly more random than those that could be thought up by a human.<br />However, if poorly implemented, password generation tools can pose a significant security risk.<br />Consider some important facts:<br /> - My friend was able to obtain a list of 500 passwords generated for sequential asset numbers without having any administrative access to his domain<br /> - The password algorithm used was easy to break, being based on a sequential generation system<br /> - The password implementation was extremely poor, using a fixed format and poor combinations of character sequences<br /><br />The organisation in question would have had a significantly more secure system if:<br /> - The tool was protected so that only administrators could access it<br /> - The algorithms used were truly random<br /> - The passwords were never sequential<br /> - The password format was not predefined<br /><br />I may explore a password generator program in my next article, to see how it could be done in a more secure way.<br /><br />If you have any queries about this article then don't hesitate to contact me.<br /><br />Have fun!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-4128631295006341792007-08-31T22:28:00.001+01:002007-08-31T22:38:20.282+01:00Bulk Password Generation Part 1I recently received a list of passwords from someone that had been generated from an administration tool in use at their organisation.<br />They were interested in knowing whether I could create a tool that would reproduce the passwords for them.<br /><br />Apparently, the way the tool worked was to generate a password using the numeric asset identifier of the PC the password was to be used on.<br />The tool produced two passwords for each PC. I am told that one is the password for the local administrator account, and the other was a password for the system BIOS.<br /><br />The list I received contained a total of 1000 passwords, two for each of the first 500 assets (0 to 499).<br /><br />The passwords were similar in appearance.<br />The first set of passwords (which I believe were the local administrator passwords) were 8 characters long, and were structured like this:<br /> UlUlUnns<br />Where U is Uppercase letter, l is lowercase letter, n is number and s was a symbol.<br />The second set of passwords (which, apparently, were the BIOS passwords) were also 8 characters long, and were structured like this:<br /> UUUUUnns<br /><br />I decided to start with the BIOS passwords (as they appeared simpler - they did not contain mixed case letters), and in this article I will discuss how the BIOS password could be broken.<br />In my next article I will examine the local administrator passwords.<br /><br />To start with, I thought it might be helpful to look at the first few passwords. The file displayed each password next to the asset number used to generate it, thus:<br />0 KCPGB76#<br />1 LDQHC87$<br />2 MERID98%<br />3 NFSJE09&<br />4 OGTKF10(<br />5 PHULG21)<br /><br />You will, as I did, notice immediately that there is a very obvious pattern to these passwords... With the exception of the symbols, each character in the password was simply moved on one place for each subsequent password!<br />Well I couldn't believe the scheme could be so simple, and to see whether this was correct, I calculated what the password would be for a few asset numbers (ignoring the symbol) and compared the results:<br />10 UMZQL76<br />15 ZREVQ21<br />20 EWJAV76<br />25 JBOFA21<br /><br />I first compared my estimate for asset 10, UMZQL76, and this seems a good match for the generated code UMZQL76& (I'll talk about the symbols in a minute).<br />The second estimate was for asset 15, which I though was ZREVQ21. This again matches ZREVQ21-.<br />My third estimate, asset 20, matches the actual EWJAV76&.<br />The fourth estimate, asset 25, broke the rule. I had estimated a password of JBOFA21. The actual password turned out to be EBOFA21-. You will notice that what I had though was a J turned out to be an E. Although other than the first letter, the password was ok.<br /><br />I decided to see where I had gone wrong. I knew that for asset 20, I had generated the correct password (ignoring the symbol), so to see where things went wrong, I estimated the next asset, 21.<br />According to the rule I had so far made, asset 21 should have produced FXKBW87. It actually produced AXKBW87.<br />Again only the first letter was out (I thought F, actual A).<br />So unlike the previous 21 assets (0-20), where the first letter had increased by one each time (with Z looping around to A), this time it had moved back from E (in asset 20) to A, a step of -4 instead of +1.<br />If I included this into my formula, that at step 21, the lettering would go back 4 but then continue adding one every time, I can successfully generate the correct first letter for assets 25, 30, 35, etc. up to asset 78.<br />At asset 78, the lettering again goes back 4, from E to A.<br />This happens again at assets 135 and 192.<br />Looking at these "special" assets together, I see that my formula breaks at these numbers:<br /> 21<br /> 78<br /> 135<br /> 192<br />At this point I decided to use some simple maths to help me along.<br />The difference between 0 and 21 is, of course, 21.<br />The difference between 21 and 78 is 57.<br />The difference between 78 and 135 is 57.<br />The difference between 135 and 192 is 57.<br />A pattern has emerged - every 57th asset, the letter goes back 4 instead of going forward one. In every case, this is going from E to A.<br /><br />To help me work things out more easily, I decided to substitute letters for numbers.<br />The most obvious way to do this was to say A=0, B=1, etc until Z=25.<br />I then examined the first few assets from 21 onwards. I chose 21 because this is the first number of the "57" sequence.<br />21 A 0<br />22 B 1<br />...<br />72 Z 25<br />73 A 0<br />74 B 1<br />75 C 2<br />76 D 3<br />77 E 4<br />78 A 0 <--- Restart sequence<br />79 B 1<br />So at asset 78, the lettering reset to start from A again (which happened to be 4(E)-4).<br /><br />I want a way to calculate which letter should be generated from the assset number. I know that 21 should give 0 (A), and 22 should give 1 (B).<br />I could do asset-21 modulus 26:<br />21-21 = 0 mod 26 = 0 (A)<br />22-21 = 1 mod 26 = 1 (B)<br />...<br />72-21 = 51 mod 26 = 25 (Z)<br />73-21 = 52 mod 26 = 0 (A)<br />...<br />77-21 = 56 mod 26 = 4 (E)<br />78-21 = 57 mod 26 = 5 (F) <--- Incorrect<br />But that would not work the as soon as we reach one of the "reset" assets...<br />I already know that the sequence resets every 57 assets.<br />What about is I tried asset modulus 57 first to get the position in the sequence?<br />20 mod 57 = 20<br />21 mod 57 = 21<br />22 mod 57 = 22<br />...<br />77 mod 57 = 20<br />78 mod 57 = 21<br />Letter 21 is a V though, and I know that the letter for asset 78 is an A.<br />Now what if I modify the asset number used to generate the code by the difference between 57 and the offset (the asset number of the password whose letter was reset to A first), which was 21?<br />So, looking at asset 21:<br />21 + (57 - 21) = 57<br />. 57 mod 57 = 0<br />. 0 = A<br />Now asset 22:<br />22 + (57 - 21) = 58<br />. 58 mod 57 = 1<br />. 1 = B<br />And a few more (replacing '(57 - 21)' with 36 for simplicity):<br />76 + 36 = 112 mod 57 = 55 (?)<br />77 + 36 = 113 mod 57 = 56 (?)<br />78 + 36 = 114 mod 57 = 0 (A)<br />However, the results for assets 76 and 77 (55 and 56) don't mean anything, but if I subsequently modulus these with 26 (the number of letters in the sequence):<br />76 + 36 = 112 mod 57 = 55 mod 26 = 3 (D)<br />77 + 36 = 113 mod 57 = 56 mod 26 = 4 (E)<br />78 + 36 = 114 mod 57 = 0 mod 26 = 0 (A)<br />That looks a bit better.<br />I tried it out on some random asset numbers between 78 and 499, and the letter was correct in all cases.<br />So the formula for the number of the first letter (remember 0=A) turns out to be:<br /> l = (n + 36) mod 57 mod 26<br />Where l is the letter code, and n is the asset number.<br /><br />Now I had figured out the first letter was generated, I tried for the next 4.<br />I took each letter and worked out what number is was in my sequence (where A=0 and Z=25), and then looked at where the sequence was disrupted (reset to A).<br />For letter 2, I noticed that the sequence was reset first at asset 39, and then subsequently at 106 and 173.<br />For letter 3, it was 30, 101 and 172.<br />For letter 4, it was 47, 126 and 205.<br />For letter 5, it was 30, 113 and 196.<br />So for letter 2, the sequence length was 67 and the modifier was 28 (67 minus the first offset 39).<br />For letter 3 the sequence length was 71 and the modifier was 41 (71 - 30).<br />For letter 4 the sequence length was 79 with a modifier of 32.<br />For letter 5 the sequence length was 83 with a modifier of 53.<br /><br />This resulted in formulae for each of these letters of:<br /> 1) l = (n + 36) mod 57 mod 26<br /> 2) l = (n + 28) mod 67 mod 26<br /> 3) l = (n + 41) mod 71 mod 26<br /> 4) l = (n + 32) mod 79 mod 26<br /> 5) l = (n + 53) mod 83 mod 26<br />Using these formulae I was able to successfully calculate the first five characters of every single password for the assets up to 499.<br /><br />Moving onto the two numbers located at positions 6 and 7 in the password, these working in much the same way as the letters, other than the character sequence is 0 - 9 and consists of 10 possibilities, instead of the 26 for the letters (A-Z).<br />Applying exactly the same method that I used above, I managed to work out a formula for the numbers of:<br /> 6) l = (n + 27) mod 99 mod 10<br /> 7) l = (n + 116) mod 197 mod 10<br /><br />Finally, the symbols are all that is left to work out.<br />Through examining the symbols that are used for various sequential codes, I managed to work out the the symbol sequence was had 10 possibilities, in the order "!#$%&()*+-".<br />Again, using the same technique described above, I managed to work out the formula for the symbols as:<br /> 8) l = (n + 101) mod 107 mod 10<br /><br />Using the formula for each character of the password, I can now generate the correct BIOS password for any asset number.<br />For example, for asset 101:<br /> 1) l = (101 + 36) mod 57 mod 26<br />. = 137 mod 57 mod 26<br />. = 23 mod 26<br />. = 23 'X'<br /> 2) l = (101 + 28) mod 67 mod 26<br />. = 129 mod 67 mod 26<br />. = 62 mod 26<br />. = 10 'K'<br /> 3) l = (101 + 41) mod 71 mod 26<br />. = 142 mod 71 mod 26<br />. = 0 mod 26<br />. = 0 'A'<br /> 4) l = (101 + 32) mod 79 mod 26<br />. = 133 mod 79 mod 26<br />. = 54 mod 26<br />. = 2 'C'<br /> 5) l = (101 + 53) mod 83 mod 26<br />. = 154 mod 83 mod 26<br />. = 71 mod 26<br />. = 19 'T'<br /> 6) l = (101 + 27) mod 99 mod 10<br />. = 128 mod 99 mod 10<br />. = 29 mod 10<br />. = 9 '9'<br /> 7) l = (101 + 116) mod 197 mod 10<br />. = 217 mod 197 mod 10<br />. = 20 mod 10<br />. = 0 '0'<br /> 8) l = (101 + 101) mod 107 mod 10<br />. = 202 mod 107 mod 10<br />. = 95 mod 10<br />. = 5 '('<br />So the final password for asset 101 is 'XKACT90('.<br /><br />Some important things to note about this password generation method:<br />WEAK TECHNIQUE<br />The technique used to generate these passwords is weak.<br />If you saw two or three sequential passwords, you would immediately sense a flaw due to the sequential nature of the generated passwords.<br />To make a highly educated guess at the formula for each character using the technique I described above, you would need less than 300 sequential passwords.<br />You could actually make a confident guess at 5 out of 8 of the character formulae with less than 150 sequential passwords.<br /><br />POOR IMPLEMENTATION<br />Whoever created the scheme had the forsight to use complex password characters, by including the numerics and symbols in the password.<br />However, because the 6th and 7th character are always numbers and the final character is always one of 10 symbols, this actually reduces the complexity of the password significantly!<br />You would only need to see two separate passwords (not even sequential) to surmise that the format was fixed, 5 letters followed by 2 numbers and a single symbol.<br />A better implementation would have been to include numbers and symbols in each character sequence for each letter, thereby increasing the complexity of the password to 46 possibilities per password character.<br /><br />EASY TO BRUTE FORCE<br />Consider that to break the password using brute force, you would currently need to break 5 letters (26 possibilities each), 2 numbers (10 possibilities each) and a symbol (10 possibilities):<br /> 26^5 x 10^3 = 11,881,376,000<br />But if a fuller implementation (letters, numbers and symbols in each character set) had been implemented (46 possibilities each):<br /> 46^8 = 20,047,612,231,936<br />This is over 1,687 times the number of combination than for the current password.<br />The math is simple 11 billion vs 20 trillion combination!<br /><br /><br />In my next article I will look at the local administrator passwords that comprise the second half of the password list I was given and discuss the use of such methods to generate password lists.<br /><br />Until then...Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-69634375039958400832007-08-21T10:13:00.000+01:002007-08-21T10:16:38.093+01:00Protecting .Net Assemblies Part 2In my last article, we looked at techniques for obfuscating the string and meta data inside our assemblies so that they could not be easily understood.<br /><br />In this article, I would like to explore another technique which I came across the other day, which basically involves hiding a compiled assembly from disassembler tools so that it cannot be disassembled easily.<br /><br />The way it worked is, in my opinion, fairly clever and although the technique has been around since long before .Net was released, and is not specifically used to prevent disassembly, it is still a very effective way of deterring casuals attempts to reverse engineer one's code.<br />Basically, the way in which this works is to produce a program in two assemblies.<br />The first assembly consists of the public face to the program. The second assembly consists of all of the actual functionality for the program.<br />In the first assembly (lets call it A), we create an Interface, which I will call IRunApp for sake of argument. The second assembly (B) references the public assembly (A), and implements the IRunApp Interface in class RunApp<br />The IRunApp Interface has a single parameterless void method which I will call Start.<br /><br />Now we compile B so that it becomes a .Net IL assembly file. We make a note of it's size (say 32K exactly for sake of argument).<br />In A, in the main startup code, we add some lines that will do the following:<br /> - Get the currently executing Assembly (A)<br /> - Get the loaded Module of this Assembly<br /> - Read the bytes from the total length of the Module - 32K to the end of the Module<br /> - Load these bytes into an Assembly (B)<br /> - Using Reflection, create an instance of the IRunApp Interface via the class RunApp in B<br /> - Execute the Start method of IRunApp in B<br />We then compile A so that it also becomes a .Net IL assembly. We then take the entire content of the file B and append it to the end of the file A (using a hex-editor or perhaps a tool you have written yourself).<br />Then we run A, and see that the the code in B has been successfully executed. If we examine the code using ILDASM, we see that only assmelby A is visible - we can see that A does something to load some code by Reflection but we do not actually have access to the code in B.<br /><br />I have produced two demos that show this functionality:<br />Demo A<br />In Demo A, there are two assemblies - the main program executable (A) and the library that will eventually become the hidden assembly (B).<br />In this demo, A loads the file content of B directly, and then invokes the IRunApp.Start() method using Reflection. This sample is there just to give you an example of how reflection works.<br />You should also examine the assemblies using ILDASM or another disassembly tool, just to see how visible the IL is in both cases (particularly in B).<br /><br />Demo B<br />In Demo B, there is a single assembly which is the program executable. This contains the main assembly and also contains the embedded assembly B, which has been embedded using the technique described above.<br />In this demo, A loads the assembly B using the technique I described in HIDING ASSEMBLIES above. B is then invoked using Reflection.<br />If you open the executable in ILDASM you will see the code disassembled that carries out the work to load and execute B but, importantly, you will not see the actual code for B.<br /><br /><br />The samples are available by clicking the links below:<br /> - <a href="http://www.memia.biz/blogs/c2o/EmbeddedDemoA.zip">Demo A</A><br /> - <a href="http://www.memia.biz/blogs/c2o/EmbeddedDemoB.zip">Demo B</A><br /><br />ADDITIONAL TECHNIQUES<br />Well assuming that you have implemented an assembly hiding method now, you are probably wondering what is to stop someone who understands the technique from simply using a hex-editor and cutting and pasting your embedded assemblies out to separate files.<br />Well the truth of the matter is that it is highly unlikely that you will ever stop someone who knows what they are doing from accessing your .Net code in this way, but you can still use a few more methods to make it more difficult:<br /> - Add fake libraries into the file<br /> You can add some fake assemblies to the end of the file, and make one of these your valid assembly. This will not make it impossible to access the real assembly but it will make it more difficult.<br /> - Encrypt your libraries<br /> You can encrypt the libraries that are embedded in the file so that they cannot just be extracted using a hex-editor. A compiled assembly has a distinctive layout, which will be completely hidden by encryption.<br /> - Use remoting or a WebService for sensitive business logic<br /> If you are able to, you can use .Net Remoting or a WebService to host your business logic and other sensitive code. You can invoke the service from your application code.<br /><br /><br />There isn't a lot more to say on the technique for hiding assemblies, other than you should make the effort to protect your source code in every way possible. People are often flippant about security, but you should not forget that your source code is your intellectual property - do you really want others to see how you do things in your applications, particularly if you are providing an application that is unique or satisfies a niche demand.<br /><br />If you have any suggestions or queries about this article, just drop me an e-mail.<br /><br />Have fun!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-74186076813287029942007-08-17T23:13:00.000+01:002007-08-17T23:17:57.291+01:00Protecting .Net Assemblies Part 1Over the next two articles, I thought it would be interesting to look at a couple of techniques to make .Net assemblies less easy to disassemble.<br /><br />Now I will presume that you already know that to disassemble a .Net assembly (EXE or DLL), all you need to do is open the assembly using the ILDASM tool, which comes as part of the Microsoft.Net SDK.<br /><br />If you don't know this already, give it a try now - open ILDASM (through the VS command prompt) and then open the latest .Net assembly you worked on using it.<br /><br />ILDASM can be used to reverse engineer most .Net projects if one so desired, but this would be a long and painstaking process. Converting IL back into VB.NET or C# is reasonably straight forward, but would require significant effort due to the sheer volume of work that would need to be done to achieve the result.<br /><br />Another much more useful tool is the .Net Reflector, which is produced by Lutz Roeder. This tool provides the same functionality as ILDASM, but in addition it can disassemble the IL into c#, VB.NET, etc., and provides some extremely useful analysis capabilities too. You can download the .Net Reflector <a href="http://www.aisto.com/roeder">here</a>.<br /><br />It is worth noting that ALL .Net assemblies are vulnerable to disassembly. This is due to the nature in which they are produced. .Net source code, such as C# or VB.NET, is compiled by a .Net compiler (such as Visual Studio.Net) into IL (Intermediate Language).<br />This is a platform independant pseudo-assembler that is compiled at run-time by the Microsoft.Net Just-In-Time (JIT) compiler into native assembler for execution on the target processor environment (typically x86 in the case of Windows).<br /><br />So, even if you were not aware that your compiled .Net code can be reversed before you red this article, I think we can all agree now that this is the case.<br /><br />How then, do we protect our valuable source code from prying eyes?<br /><br />A quick, simple and relatively effective method is to apply obfuscation to your code.<br />This involves using an additional tool to "scramble" the metadata and string portions of the code so that they are not readable by ILDASM and other such tools.<br /><br />If, for instance, you had a MessageBox.Show in your code that display a message "Hello World", the obfuscation tool would replace "Hello World" with an encrypted byte sequence. When examined in a disassembly tool, the byte sequence would be unreadable and, thus, it becomes more difficult to understand what is happening in the program.<br /><br />As well as strings, the metadata portion of the assembly is scrambled, so that the names of objects, methods, properties, etc. are replaced by a single unprintable character. This is most effective because if you had a method named something like "CheckPassword", which would be readable in the disassembly tool and clearly shows what the method does, it would be replaced by a single character which doesn't mean anything.<br /><br />Unfortunately, obfuscation does not make it impossible to disassemble a .Net assembly. In fact, it doesn't really even make it difficult, because the raw code is still available in IL. It can be disassembled, and analysis of the code will, in time, reveal the purpose of most of the code portions.<br /><br />Even the string data is not secure. Analysis of the code will reveal that each time a string (or obfuscated byte sequence) is used, a method is invoked which accepts the byte sequence (and sometimes an integer seed) as a parameter and returns a string. This is the byte decryption method, and the code for this is, sadly, freely available inside the .Net assembly that was obfuscated.<br />I have produced a tool myself that can break the byte sequence encryption for any string obfuscated by the Dotfuscator tool.<br /><br />In conclusion, obfuscation adds another layer of protection to our assembly, but it doesn't protect the code in any way, so what else could be done to make the code more secure?<br /><br />In my next article I will be exploring another tecnique, which should provide another layer of protection from prying eyes... assembly hiding.<br /><br />Until next time...Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-21499001167343552722007-08-15T20:21:00.001+01:002007-08-15T20:36:11.271+01:00The Outlook PST BreakerWell it's been too long since I last wrote, so my apologies for that.<br /><br />Here is the promised PST password tool.<br /><br />I attach a screenshot:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZOtlN_PHQMmz9Bk-FuQx7mEnAV_dzFuTfJFfctWZVj0HD0agxWSoGtfA6R68SthKBeIAzhS3eGLwrRWpjJMq3XFTn4rB7xJ2sFJA-tpc0l7eKAns-sHEgt5WFxLGno0jT3NejrK65Vr0/s1600-h/PstBreaker.GIF"><img style="cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZOtlN_PHQMmz9Bk-FuQx7mEnAV_dzFuTfJFfctWZVj0HD0agxWSoGtfA6R68SthKBeIAzhS3eGLwrRWpjJMq3XFTn4rB7xJ2sFJA-tpc0l7eKAns-sHEgt5WFxLGno0jT3NejrK65Vr0/s400/PstBreaker.GIF" alt="" id="BLOGGER_PHOTO_ID_5099010105878814306" border="0" /></a><br /><br />The tool has the following features:<br /><u>Encrypt a password</u><br />Enter a password into the "Password" textbox and click the Encrypt button.<br /><br />You will see in the main output window all of the steps taken to encrypt the password.<br /><br /><u>Attempt to cryptographically break a 32-bit password code</u><br />Enter a password code into the "Pw Code" textbox, and select options to help the break. Then click the Decrypt button.<br /><br />As previously discussed (in my earlier article), using a password length limit, character substitution and a smaller character set will result in significantly faster breaking.<br /><br />The password code already in the "Pw Code" textbox will break to "adad". If you turn on character substitution, it will break to "¹muleb", in about half the time of the "adad" break.<br /><br /><u>Show verbox output</u><br />Turn this on to see extended information generated during the break. This will slow down the break significantly - it will be in excess of 10 times slower!<br /><br /><br />The tool is located <a href="http://www.memia.biz/blogs/c2o/PstBreak.exe">here</a>.<br /><br />Let me know if you have any suggestions for it.<br /><br />Until next time!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-54773760483925520432007-07-12T22:51:00.000+01:002007-07-12T22:52:53.038+01:00Outlook PST Password Decryption<font face="Trebuchet MS" size="2"><P>In my previous article I looked at how encryption worked for Microsoft Outlook PSTs. In this article I am going to see if the encryption is reversable and if coded passwords can be decrypted.</P><P>Lets look again at the encryption of 'adad' (based on the content of my previous article):</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="100">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>1</TD><TD>'a' 0x61 (97)</TD><TD>0x00000000</TD><TD>0x00</TD><TD>0x61 (97)</TD><TD>0x00000000</TD><TD>0x3AB551CE</TD><TD>0x3AB551CE</TD></TR><TR><TD>2</TD><TD>'d' 0x64 (100)</TD><TD>0x3AB551CE</TD><TD>0xCE</TD><TD>0xAA (170)</TD><TD>0x003AB551</TD><TD>0x36034AF6</TD><TD>0x3639FFA7</TD></TR><TR><TD>3</TD><TD>'a' 0x61 (97)</TD><TD>0x3639FFA7</TD><TD>0xA7</TD><TD>0xC6 (198)</TD><TD>0x003639FF</TD><TD>0x72076785</TD><TD>0x72315E7A</TD></TR><TR><TD>4</TD><TD>'d' 0x64 (100)</TD><TD>0x72315E7A</TD><TD>0x7A</TD><TD>0x1E (30)</TD><TD>0x0072315E</TD><TD>0xFA0F3D63</TD><TD>0xFA7D0C3D</TD></TR></TBODY></TABLE></FONT><P>As can be seen, 'adad' is encrypted to 0xFA7D0C3D in 4 steps.</P><P>So, how can we get from 0xFA7D0C3D to 'adad'? At first glance I think it isn't possible.</P><P>Consider the way the password is encrypted. After iteration 1, we have a NV of 0x3AB551CE, which is then right-shifted in iteration 2 so that the 0xCE component is lost. It simply isn't possible to get from the NV 0x3639FFA7 in iteration 2 back to a PV of 0x3AB551CE. The best we could possibly do is get to 0x3AB551??. In addition, there is no way to calculate BV or C at any iteration, because we need two parts of either P, BV or C.</P><P>Unfortunately, it appears the only way to decrypt the password is to break it. The encryption is not reversible.</P><P>To start the break, I have the value 0xFA7D0C3D, and a list of potential modifier (M) values. Now remember, as I am reversing and breaking the encryption, I am working backwards. The first value I am using is for the last character of the password.</P><P>The first thing I do is work out all the possible modifier values that could have been applied to the value I have. This is easy to work out - because my value (NV) starts with 0xFA, I just need to find any modifiers that start with 0xFA, which yields the following:</P><OL><LI>0xFA0F3D63 - 0x001E</LI><LI>0xFAF83322 - 0x0177</LI></OL><P>Now we already know that modifiers at positions higher than 0xFF cannot be generated with the ASCII character set (from my previous article on encryption), so I can discard modifier number 2, which leaves me with a single possible modifier, 0xFA0F3D63.</P><P>Right, so I now have a value, a modifier and a position. From these, I can calculate a shifted value, which is 0x0072315E (V XOR M), which will give me a PV of 0x72315E?? (left-shift the SV by 8 bits). This gives me the following:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>?</TD><TD>'?' 0x??</TD><TD>0x72315e??</TD><TD>0x??</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>Now I still have no chance of calculating BV or C from P alone, but I can extrapolate potential values for these. I am going to substitute C for various different characters, and then XOR these with P to get an assumed BV. Technically, I should submit C for any valid character from the ASCII character set, but for the purposes of this article I am only going to work with the characters 'a' and 'd'. Any final decryption method would clearly need to implement a much larger character set.</P><P>Lets have a look at what results we get with each character:</P><UL><LI>'a' is character code 0x61, which would give BV = 0x61 XOR 0x1E (C XOR P), which gives a BV of 0x7F. This would result in a PV of 0x72315E7F.</LI><LI>'d' is character code 0x64, which would give BV = 0x7A. This would result in a PV of 0x72315E7A.</LI></UL><P>Because I have no way of knowing which PV is the correct value, I need to check each of them.</P><P>So, I use the first PV, 0x72315E7F (which came from character 'a'). I repeat the same process for this value as I did above for the first value (0xFA7D0C3D). This gives only one potential modifier, 0x72076785 from position 0xC6. I now calculate a potential SV and PV as so:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-1</TD><TD>'?' 0x??</TD><TD>0x3639fa??</TD><TD>0x??</TD><TD>0xc6</TD><TD>0x003639fa</TD><TD>0x72076785</TD><TD>0x72315e7f</TD></TR><TR><TD>?</TD><TD>'a' 0x61</TD><TD>0x72315e7f</TD><TD>0x7f</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>And again I repeat the same process of calculating the BV through character substitution, which gives the following:</P><UL><LI>C = 'a', BV = 0x61 XOR 0xC6, BV = 0xA7, PV = 0x3639FAA7</LI><LI>C = 'd', BV = 0x64 XOR 0xC6, BV = 0xA2, PV = 0x3639FAA2</LI></UL><P>Following this I now take the PV 0x3639FAA7 and run it through the same process. This results in the following modifiers:</P><OL><LI>0x36034AF6 - 0x00AA</LI><LI>0x36b8DEAF - 0x01B7</LI></OL><P>Now I know that modifier positions above 0xFF aren't permitted so I can discard modifier 2, but again modifer 1 is valid so I calculate SV and potential PV with this:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-2</TD><TD>'?' 0x??</TD><TD>0x3ab051??</TD><TD>0x??</TD><TD>0xaa</TD><TD>0x003ab051</TD><TD>0x36034af6</TD><TD>0x3639faa7</TD></TR><TR><TD>-1</TD><TD>'a' 0x61</TD><TD>0x3639faa7</TD><TD>0xa7</TD><TD>0xc6</TD><TD>0x003639fa</TD><TD>0x72076785</TD><TD>0x72315e7f</TD></TR><TR><TD>?</TD><TD>'a' 0x61</TD><TD>0x72315e7f</TD><TD>0x7f</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>And again I repeat the same process of calculating the BV, which gives the following possibilities:</P><UL><LI>C = 'a', BV = 0x61 XOR 0xAA, BV = 0xCB, PV = 0x3ab051CB</LI><LI>C = 'd', BV = 0x64 XOR 0xAA, BV = 0xCE, PV = 0x3ab051CE</LI></UL><P>So I take the PV ox 0x3AB051CB and run it again through the same process. This gives a single potential modifier of 0x3AB551ce at position 0x61.</P><P>If I repeat the SV and PV calculations with this modifier, it gives me the following:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-3</TD><TD>'?' 0x??</TD><TD>0x050005??</TD><TD>0x??</TD><TD>0x61</TD><TD>0x00050005</TD><TD>0x3ab551ce</TD><TD>0x3ab051cb</TD></TR><TR><TD>-2</TD><TD>'a' 0x61</TD><TD>0x3ab051cb</TD><TD>0xcb</TD><TD>0xaa</TD><TD>0x003ab051</TD><TD>0x36034af6</TD><TD>0x3639faa7</TD></TR><TR><TD>-1</TD><TD>'a' 0x61</TD><TD>0x3639faa7</TD><TD>0xa7</TD><TD>0xc6</TD><TD>0x003639fa</TD><TD>0x72076785</TD><TD>0x72315e7f</TD></TR><TR><TD>?</TD><TD>'a' 0x61</TD><TD>0x72315e7f</TD><TD>0x7f</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>I recalcaulte BV, which gives these possibilites:</P><UL><LI>C = 'a', BV = 0x61 XOR 0x61, BV = 0x00, PV = 0x05000500</LI><LI>C = 'd', BV = 0x64 XOR 0x61, BV = 0xCE, PV = 0x05000505</LI></UL><P>Lets again take the first PV, 0x05000500, and run it through the same process, which yields a single modifier of 0x05005713 at position 0xC7.</P><P>This time, if I calculate the SV and PV values, I get:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-4</TD><TD>'?' 0x??</TD><TD>0x005213??</TD><TD>0x??</TD><TD>0xc7</TD><TD>0x00005213</TD><TD>0x05005713</TD><TD>0x05000500</TD></TR><TR><TD>-3</TD><TD>'a' 0x61</TD><TD>0x05000500</TD><TD>0x00</TD><TD>0x61</TD><TD>0x00050005</TD><TD>0x3ab551ce</TD><TD>0x3ab051cb</TD></TR><TR><TD>-2</TD><TD>'a' 0x61</TD><TD>0x3ab051cb</TD><TD>0xcb</TD><TD>0xaa</TD><TD>0x003ab051</TD><TD>0x36034af6</TD><TD>0x3639faa7</TD></TR><TR><TD>-1</TD><TD>'a' 0x61</TD><TD>0x3639faa7</TD><TD>0xa7</TD><TD>0xc6</TD><TD>0x003639fa</TD><TD>0x72076785</TD><TD>0x72315e7f</TD></TR><TR><TD>?</TD><TD>'a' 0x61</TD><TD>0x72315e7f</TD><TD>0x7f</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>However, this time I know there aren't any possibilites. A PV of less than 0x01000000 will not yield any modifiers, because there are none that start with 0x00. This means that I know there are no valid letter combinations below where I am now, '?aaaa'.</P><P>So I can discard this particular path and move back up to the next possibility, which is at '?daaa'. This has an identical modifier list (because it also starts with a NV of 0x05) and I already know that this will not yield a valid PV, so I can also discard this possibility.</P><P>This means I now need to move on to the next possibility, which begins at '?daa'.</P><P>I repeat the same process over and over, moving through the other potentials, until I manage to dismiss all possibilites that start '?a'. So I know that the password must be '?d', that is it ends with a 'd'.</P><P>So now if I go back to where I started, but work with a 'd' instead of an 'a', I get the following:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-1</TD><TD>'?' 0x??</TD><TD>0x3639ff??</TD><TD>0x??</TD><TD>0xc6</TD><TD>0x003639ff</TD><TD>0x72076785</TD><TD>0x72315e7a</TD></TR><TR><TD>?</TD><TD>'d' 0x64</TD><TD>0x72315e7a</TD><TD>0x7a</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>I then reapply the same rules as before, which dismisses the combinations 'aaad' and 'daad', until I reach '?dad':</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-3</TD><TD>'?' 0x??</TD><TD>0x000000??</TD><TD>0x??</TD><TD>0x61</TD><TD>0x00000000</TD><TD>0x3ab551ce</TD><TD>0x3ab551ce</TD></TR><TR><TD>-2</TD><TD>'d' 0x64</TD><TD>0x3ab551ce</TD><TD>0xce</TD><TD>0xaa</TD><TD>0x003ab551</TD><TD>0x36034af6</TD><TD>0x3639ffa7</TD></TR><TR><TD>-1</TD><TD>'a' 0x61</TD><TD>0x3639ffa7</TD><TD>0xa7</TD><TD>0xc6</TD><TD>0x003639ff</TD><TD>0x72076785</TD><TD>0x72315e7a</TD></TR><TR><TD>?</TD><TD>'d' 0x64</TD><TD>0x72315e7a</TD><TD>0x7a</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>Now you'll see we have a P of 0x61, and a SV of 0x0. Look what happens if I calculate the possible BV by using character substitution of C:</P><UL><LI>C = 'a', BV = 0x61 XOR 0x61, BV = 0x00, PV = 0x00000000</LI><LI>C = 'd', BV = 0x64 XOR 0x61, BV = 0x05, PV = 0x00000005</LI></UL><P>We know the 'd' cannot be valid because a PV of 0x5 is below the minimum allowed, which is 0x01000000, but look at the 'a' - it results in a PV of 0x0. This means there are no further calculations to do - we have broken the password - and given a final result of 'adad':</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="50">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>-3</TD><TD>'a' 0x61</TD><TD>0x0000000</TD><TD>0x00</TD><TD>0x61</TD><TD>0x00000000</TD><TD>0x3ab551ce</TD><TD>0x3ab551ce</TD></TR><TR><TD>-2</TD><TD>'d' 0x64</TD><TD>0x3ab551ce</TD><TD>0xce</TD><TD>0xaa</TD><TD>0x003ab551</TD><TD>0x36034af6</TD><TD>0x3639ffa7</TD></TR><TR><TD>-1</TD><TD>'a' 0x61</TD><TD>0x3639ffa7</TD><TD>0xa7</TD><TD>0xc6</TD><TD>0x003639ff</TD><TD>0x72076785</TD><TD>0x72315e7a</TD></TR><TR><TD>?</TD><TD>'d' 0x64</TD><TD>0x72315e7a</TD><TD>0x7a</TD><TD>0x1e</TD><TD>0x0072315e</TD><TD>0xfa0f3d63</TD><TD>0xfa7d0c3d</TD></TR></TBODY></TABLE></FONT><P>Now, I have demonstrated that the password encryption can be broken, and we can definitely get the valid password from the final coded value.</P><P>However, breaking the password in this way is very expensive. I have listed some important points that can affect the performance of the break:</P><P><U>CHARACTER SET</U><BR>If you consider that at each level there are 223 (0xDF) ASCII character possibilities (assuming that control characters below 0x20 are ignored), and that there may be many possible modifiers at each level (up to 4), this means that at each level there could be 892 possibilities.</P><P>This is ok if the password is very short, but for a password of length 5 there are 564,708,431,199,232 combinations (over 564 trillion). At length 10 there are 318,895,612,267,497,741,289,677,389,824 (over 318 trillion trillion)!</P><P>We can reduce the cost of breaking passwords significantly if we make assumptions during the character substitution stage. We could work with specific character sets, which would reduce the cost as so:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="75">Set</TD><TD WIDTH="80">Poss (1)</TD><TD WIDTH="175">Poss (length 5)</TD><TD WIDTH="350">Poss (length 10)</TD></TR><TR><TD>All 223</TD><TD ALIGN="RIGHT">892</TD><TD ALIGN="RIGHT">564,708,431,199,232</TD><TD ALIGN="RIGHT">318,895,612,267,497,741,289,677,389,824</TD></TR><TR><TD>0-9A-Za-z</TD><TD ALIGN="RIGHT">248</TD><TD ALIGN="RIGHT">938,120,019,968</TD><TD ALIGN="RIGHT">880,069,171,864,760,718,721,024</TD></TR><TR><TD>a-z</TD><TD ALIGN="RIGHT">104</TD><TD ALIGN="RIGHT">12,166,529,024</TD><TD ALIGN="RIGHT">148,024,428,491,834,392,576</TD></TR></TBODY></TABLE></FONT><P>As you can see, reducing the available character set would make a huge difference to the number of possibilities. The scenario listed above, however, assumes the worst case - that there are 4 valid modifiers at each level, which is unlikely. For most PV there are 1 or 2 modifier values.</P><P><U>CHARACTER POSITIONING</U><BR>In the English alphabet, certain letters are much more likely to appear in words than others.</P><P>Using this information, we could order the characters so the most likely characters to be used come first, which means more likely letter combinations are broken earlier in the process.</P><P>A good example would be to put the letter 'e' before all others, because it is the most common letter used in English words. Letters such as 'q' could be placed at the end of the list or maybe excluded altogether - just taking 'j' and 'q' out of the character set 'a-z' would reduce the possibilities in a 10 letter password by 55% - 80,000 trillion.</P><P><U>PASSWORD LENGTH</U><BR>We know that the maximum password length for a PST password is 15 characters.</P><P>Using this knowledge, we can ensure that we do not waste time calculating impossible passwords. As soon as we reach a 16th decryption step, we can assume that this is not a possible password.</P><P>Additionally, we can save significant time in processing if we make an assumption about the password length.</P><P>Consider the following, if I have to calculate all the possible passwords for the character set 'a-z' to a length of 15 characters with the maximum 4 modifiers at each level, there are ((26 * 4) to the 15) possibilities - an amazing 1,800,943,505,506,915,684,277,314,125,824!</P><P>However, if I assume the maximum password size is 8, then this becomes ((26 * 4) to the 8) possibilities - a mere 13,685,690,504,052,736. This is over 131 trillion times less possibilities.</P><P>Obviously this is several orders of magniture less, and will require significantly less effort to break.</P><P><U>LOWEST LEVEL LETTER SUBSTITUTION</U><BR>At the bottom level of a decryption break, where there is a NV of 0, we might have a remaining character that is not part of our character set.</P><P>A good example is the password 'fred', which encrypts to 0x1B6D2E42.</P><P>This password can be broken using the standard method, but by allowing the lowest letter of the password to be substituted by any valid ASCII character, it is actually possible to break this faster. The result is the password '¹mrzab', which can be copied and pasted into Outlook.</P><P>If we have assumed our password length is 8 or less characters, this will result in a significantly faster break (over 50%) for passwords such as these, and there is no additional cost involved for us in allowing this.</P><P>The only issue is that you may not necessarily obtain the original password.</P><P> </P><P>Well that concludes my work on Outlook PST password decryption. I believe I have successfully demonstrated that Outlook PST passwords are vulnerable.</P><P>Although, as with SourceSafe passwords, I wonder whether there is really a problem that the passwords are vulnerable. Anyone who is concerned about keeping the e-mail very secure will no doubt implement Microsoft Exchange with Active Directory integrated security - which is infinitely more secure than a PST on the desktop.</P><P>As always, if you want to keep your data secure use a long password with mixed case letters, numbers and symbols (if permitted). Using such a technique with Outlook PSTs would significantly increase the amount of work required to perform a break by several orders of magnitude. You have been warned...</P></font>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-27096773708668552192007-07-11T20:34:00.000+01:002007-07-11T20:36:27.424+01:00Outlook PST Password Encryption<font face="Trebuchet MS" size="2"><P>In my previous article about Microsoft Outlook, I demonstrated how secured Outlook Data Files (PSTs) could be accessed without having the password for them.</P><P>During the article, I noticed a call that took my entered password as a criteria and returned a coded value that was then compared to a value on the stack.</P><P>I believe that this is where the password is encrypted and today I want to take a look at how this works.</P><P>First of all, referring to my previous article, there is a call at +523B2 in <I>MSPST32</I>, which has a parameter of my previous password:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="100">+523B1</TD><TD WIDTH="150">PUSH</TD><TD WIDTH="500">EAX</TD></TR><TR><TD>+523B2</TD><TD>CALL</TD><TD>MSPST32.+55AAF</TD></TR></TABLE></TBODY></FONT><P>In this case, <I>EAX</I> contains the password I entered, 'fred'. When I step over the <I>CALL</I> at +523B2, I notice that <I>EAX</I> now contains the value 0x1B6D2E42 which, for now, I will assume is the coded value of my password.</P><P>Then, later on in the proc, at +523CC, this value (which, in the mean time, has been copied to <I>EBX</I>) is compared with the value at <I>ESI</I>-1C, which is 0xFA7D0C3D.</P><P>The result is that they are not equal and a dialog is displayed informing me that the password I entered is incorrect.</P><P>Now to double check that I am looking in the right place, I enter what I know to be the correct password, 'adad'. The <I>CALL</I> at +523B2 this time sets <I>EAX</I> to 0xFA7D0C3D, which is the same as the value that it will be compared with at +523CC, so I know that this must be where the encryption takes place. If I run the code from here, I see that the incorrect password dialog is skipped over and the PST file is opened.</P><P>So, to start looking at the encryption, I set a breakpoint at +523B2 in <I>OllyDBG</I>, and then step into the proc that is called.</P><P>The proc has the following code:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="100">+55AAF</TD><TD WIDTH="150">PUSH</TD><TD WIDTH="500">DWORD PTR SS:[ESP+4]</TD></TR><TR><TD>+55AB3</TD><TD>CALL</TD><TD><&MSVCRT.strlen></TD></TR><TR><TD>+55AB8</TD><TD>CMP</TD><TD>EAX, 0F</TD></TR><TR><TD>+55ABB</TD><TD>POP</TD><TD>ECX</TD></TR><TR><TD>+55ABC</TD><TD>JBE</TD><TD>MSPST32.+55AC1</TD></TR><TR><TD>+55ABE</TD><TD>PUSH</TD><TD>0F</TD></TR><TR><TD>+55AC0</TD><TD>POP</TD><TD>EAX</TD></TR><TR><TD>+55AC1</TD><TD>PUSH</TD><TD>EAX</TD></TR><TR><TD>+55AC2</TD><TD>PUSH</TD><TD>DWORD PTR SS:[ESP+8]</TD></TR><TR><TD>+55AC6</TD><TD>PUSH</TD><TD>0</TD></TR><TR><TD>+55AC8</TD><TD>CALL</TD><TD>MSPST32.+2AF7</TD></TR><TR><TD>+55ACD</TD><TD>RETN</TD><TD>4</TD></TR></TABLE></TBODY></FONT><P>You will quickly see that all this proc is doing is calculating the password length. If the password is longer than the maximum (0xF), the length is set to 0xF (and stored in <I>EAX</I>).</P><P>The proc then calls another proc at +2AF7, which I step into.</P><P>This proc has the following code:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="100">+2AF7</TD><TD WIDTH="150">PUSH</TD><TD WIDTH="500">EBP</TD></TR><TR><TD>+2AF8</TD><TD>MOV</TD><TD>EBP, ESP</TD></TR><TR><TD>+2AFA</TD><TD>MOV</TD><TD>ECX, DWORD PTR SS:[EBP+10]</TD></TR><TR><TD>+2AFD</TD><TD>MOV</TD><TD>EAX, DWORD PTR SS:[EBP+C]</TD></TR><TR><TD>+2B00</TD><TD>TEST</TD><TD>ECX, ECX</TD></TR><TR><TD>+2B02</TD><TD>JBE</TD><TD>MSPST32.+2B25</TD></TR><TR><TD>+2B04</TD><TD>PUSH</TD><TD>ESI</TD></TR><TR><TD>+2B05</TD><TD>MOVZX</TD><TD>EDX, BYTE PTR DS:[EAX]</TD></TR><TR><TD>+2B08</TD><TD>MOVZX</TD><TD>ESI, BYTE PTR SS:[EBP+8]</TD></TR><TR><TD>+2B0C</TD><TD>XOR</TD><TD>EDX, ESI</TD></TR><TR><TD>+2B0E</TD><TD>MOV</TD><TD>ESI, DWORD PTR SS:[EBP+8]</TD></TR><TR><TD>+2B11</TD><TD>SHR</TD><TD>ESI, 8</TD></TR><TR><TD>+2B14</TD><TD>MOV</TD><TD>EDX, DWORD PTR DS:[EDX*4+7100C]</TD></TR><TR><TD>+2B1B</TD><TD>XOR</TD><TD>EDX, ESI</TD></TR><TR><TD>+2B1D</TD><TD>INC</TD><TD>EAX</TD></TR><TR><TD>+2B1E</TD><TD>DEC</TD><TD>ECX</TD></TR><TR><TD>+2B1F</TD><TD>MOV</TD><TD>DWORD PTR SS:[EBP+8], EDX</TD></TR><TR><TD>+2B22</TD><TD>JNZ</TD><TD>MSPST32.+2B05</TD></TR><TR><TD>+2B24</TD><TD>POP</TD><TD>ESI</TD></TR><TR><TD>+2B25</TD><TD>MOV</TD><TD>EAX, DWORD PTR SS:[EBP+8]</TD></TR><TR><TD>+2B28</TD><TD>POP</TD><TD>EBP</TD></TR><TR><TD>+2B29</TD><TD>RETN</TD><TD>0C</TD></TR></TABLE></TBODY></FONT><P>Now this is starting to look more like it.</P><P>The first few lines, in +2AF8 to +2B02 simply check to see whether the password has a length and sets <I>ECX</I> to the length of the password.</P><P>There is a loop between +2B05 to +2B22. If I examine the loop in detail, we can see the following occuring:</P><UL><LI>+2B05 - The next character code for the next character from my password is moved into <I>EDX</I>.</LI><LI>+2B08 - The lowest order byte of the DWORD value held at <I>EBP</I>+8 is moved into <I>ESI</I>. This is 0 on the first iteration of the loop.</LI><LI>+2B0C - The character code of the current letter (which is in <I>EDX</I>) is <I>XOR</I>ed with the byte in <I>ESI</I> and is stored in <I>EDX</I>.</LI><LI>+2B0E - The value held at <I>EBP</I>+8 is moved into <I>ESI</I>. This is 0 on the first iteration of the loop.</LI><LI>+2B11 - The value in <I>ESI</I> is right-shifted 8 bits.</LI><LI>+2B14 - A 32-bit modifier value is loaded into <I>EDX</I> from the data segment of the <I>MSPST</I> module (I will talk more about this in a minute). The position of the value is offset by 4*<I>EDX</I> (or essentialy <I>EDX</I> DWORDs). <I>EDX</I> contains the character code which was XORed at +2B0C.</LI><LI>+2B1B - The value in <I>EDX</I> (the modifier) is <I>XOR</I>ed with value in <I>ESI</I>, and the result is stored in <I>EDX</I></LI><LI>+2B1D - The position of the next character is incremented</LI><LI>+2B1E - The loop counter is decremented</LI><LI>+2B1F - The value in <I>EDX</I> is stored back in <I>EBP</I>+8 for the next loop iteration.</LI><LI>+2B22 - Loop unless <I>ECX</I> = 0</LI></UL><P>This process takes place for each character in the entered password.</P><P>The modifier value I mentioned, which is loaded into <I>EDX</I> at +2B14, is used to "encrypt" each character in the password. There is a predifined list of 575 32-bit values in the list. All are different, with the exception of the last 128 values, which are all 0xAAAAAAAA.</P><P>It is important to note though, that as I am using the ASCII character set, it is only possible to use the first 256 values (0-0xFF), as any value in the range 0-0xFF <I>XOR</I>ed with any value in the range 0-0xFF can only yield a result of 0-0xFF.</P><P>So, based on what I have discovered in the above loop, lets look at how 'adad' will be encrypted:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="40">It</TD><TD WIDTH="100">C</TD><TD WIDTH="100">PV</TD><TD WIDTH="50">BV</TD><TD WIDTH="100">P</TD><TD WIDTH="100">SV</TD><TD WIDTH="100">M</TD><TD WIDTH="100">NV</TD></TR><TR><TD>1</TD><TD>'a' 0x61 (97)</TD><TD>0x00000000</TD><TD>0x00</TD><TD>0x61 (97)</TD><TD>0x00000000</TD><TD>0x3AB551CE</TD><TD>0x3AB551CE</TD></TR><TR><TD>2</TD><TD>'d' 0x64 (100)</TD><TD>0x3AB551CE</TD><TD>0xCE</TD><TD>0xAA (170)</TD><TD>0x003AB551</TD><TD>0x36034AF6</TD><TD>0x3639FFA7</TD></TR><TR><TD>3</TD><TD>'a' 0x61 (97)</TD><TD>0x3639FFA7</TD><TD>0xA7</TD><TD>0xC6 (198)</TD><TD>0x003639FF</TD><TD>0x72076785</TD><TD>0x72315E7A</TD></TR><TR><TD>4</TD><TD>'d' 0x64 (100)</TD><TD>0x72315E7A</TD><TD>0x7A</TD><TD>0x1E (30)</TD><TD>0x0072315E</TD><TD>0xFA0F3D63</TD><TD>0xFA7D0C3D</TD></TR><TR><TD> </TD><TD COLSPAN="7">It = loop iteration</TD></TR><TR><TD> </TD><TD COLSPAN="7">C = character</TD></TR><TR><TD> </TD><TD COLSPAN="7">PV = previous value (from previous iteration), <I>EBP</I>+8</TD></TR><TR><TD> </TD><TD COLSPAN="7">BV = lowest order byte of PV (PV = <I>EBP</I>+8)</TD></TR><TR><TD> </TD><TD COLSPAN="7">P = Position for modifier value, result of C <I>XOR</I> BV (at +2B0C)</TD></TR><TR><TD> </TD><TD COLSPAN="7">SV = Shifted value, result of PV >> 8 (at +2B11)</TD></TR><TR><TD> </TD><TD COLSPAN="7">M = Modifier value, looked up from position of data segment + P * 4 (at +2B14)</TD></TR><TR><TD> </TD><TD COLSPAN="7">NV = New value, result of SV <I>XOR</I> M (at +2B1B)</TD></TR></TBODY></TABLE></FONT><P>So you will see from the table above, the 'adad' will give a final value of 0xFA7D0C3D, which is as expected.</P><P>In conclusion, I have managed to understand how Outlook PST password encryption takes place. As with SourceSafe's password encryption, this has some potential weaknesses, although it does appear that the encryption for Outlook PST passwords is slightly stronger than SourceSafe's.</P><P>In my next article, I hope to look at the weaknesses in the encryption and see if there may be a way to decrypt the password from the encrypted password code.</P></font>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-56573027763403056752007-07-10T21:04:00.000+01:002007-07-10T21:09:52.214+01:00Microsoft Outlook PSTs: Safe or not?<font face="Trebuchet MS" size="2"><P>Well I had such a lot of fun looking at SourceSafe password protection, I thought I'd move on to another product that uses password protection, Microsoft Outlook.</P><P>I am working with Microsoft Outlook 2002 (10.6516.6626) SP3 at the moment, so I can't guarantee that any of the information included in this article will work for any other version.</P><P>The protection I am interested in today is protection on the Outlook Data (.PST) Files. I want to know if I can access the PST file data without a password, even if it is "secured" with one.</P><P>I have created a new PST file and set it to use password protection, with a password of 'adad'.</P><P>Upon opening Outlook, I try to open the PST (File -> Open -> Outlook Data File...) at which point I am presented with a password request dialog.</P><P>I type in a password ('fred') and click OK, to be presented with a message box telling me the password is incorrect.</P><P>At this point, I attach to Outlook using <i>OllyDBG</i> and start having a look around:</P><OL><LI>Start Debug in "Execute until user code" mode</LI><br /><LI>Click OK on the wrong password dialog</LI><br /><LI>Breakpoint hit in <i>OllyDBG</i> in a message proc in the module <i>MSPST32</i></LI><br /><LI>I want to get out of the message proc into something more useful so I start Debug again in "Execute until Return" mode</LI><br /><LI>Return from the proc, and the next one (it is the same thing)</LI><br /><LI>Find myself in the proc +2390 which is starting to look more interesting</LI><br /><LI>Notice a call to <i>GetDlgItemTextA</i> in the proc, which I guess is when the password I have entered is read, so set a breakpoint on the next line (+23AE)</LI><br /><LI>Run the code, and retry the password</LI><br /><LI>Breakpoint hits at +23AE, and notice my password ('fred') at <i>EBP</i>-10</LI></OL><P>The code looks like this in the proc I am examining:</P><font face="Courier New"><TABLE><TBODY><TR><TD WIDTH="100">+23A8</TD><TD WIDTH="150">CALL</TD><TD WIDTH="500">NEAR DWORD PTR DS:[<&USER32.GetDlgItemTextA>]</TD></TR><TR><TD>+23AE</TD><TD>LEA</TD><TD>EAX, DWORD PTR SS:[EBP-10]</TD></TR><TR><TD>+23B1</TD><TD>PUSH</TD><TD>EAX</TD></TR><TR><TD>+23B2</TD><TD>CALL</TD><TD>MSPST32.+5AAF</TD></TR><TR><TD>+23B7</TD><TD>MOV</TD><TD>EBX, EAX</TD></TR><TR><TD>+23B9</TD><TD>PUSH</TD><TD>10</TD></TR><TR><TD>+23BB</TD><TD>LEA</TD><TD>EAX, DWORD PTR SS:[EBP-10]</TD></TR><TR><TD>+23BE</TD><TD>PUSH</TD><TD>0A</TD></TR><TR><TD>+23C0</TD><TD>PUSH</TD><TD>EAX</TD></TR><TR><TD>+23C1</TD><TD>CALL</TD><TD><&MSVCRT.memset></TD></TR><TR><TD>+23C6</TD><TD>MOV</TD><TD>ESI, DWORD PTR SS:[EBP+C]</TD></TR><TR><TD>+23C9</TD><TD>ADD</TD><TD>ESP, 0C</TD></TR><TR><TD>+23CC</TD><TD>CMP</TD><TD>DWORD PTR DS:[esi+1C], EBX</TD></TR><TR><TD>+23CF</TD><TD>JE</TD><TD>MSPST32.+2410</TD></TR></TBODY></TABLE></font><P>Upon stepping through the code, I can see my password being passed into the proc called at +23B2, and a value being returned in <I>EAX</I> from this. I presume that this proc is where the password is coded to whatever format is used by Outlook (I may explore this another day).</P><P>If I step down to the <I>CMP</I> at +23CC, I notice that the value in <I>EAX</I> (which was moved to <I>EBX</I>), is compared with a value at <I>ESI</I>+1C. If the value is different (which it will be), the <I>JE</I> is not taken at +23CF. If the <I>JE</I> is not taken, it is in the code following this point that the invalid password dialog is displayed to me. This leads me to concluce the <I>ESI</I>+1C must contain the password that is associated with the PST file.</P><P>To see if this is where the password is verified, I force the <I>JE</I> at +23CF by changing the <I>Z</I> register to on (1) and then continue execution - and the PST file opens in Outlook, and I have full access to it!</P><P>What is also interesting is that if I close the PST, and then reopen it (without closing Outlook) I am not presented with the password dialog again - it just opens as it did the first time. Outlook seems to cache the fact that the PST can be opened during this session and doesn't recheck the password security.</P><P>Just to see whether I can remove the security without manually forcing the <I>JE</I> at +23CF every time, I modify the <I>JE</I> to a <I>JMP</I>. I can then open any password protected PST by entering any password I want.</P><P>However, it is worth noting that modfiying the <I>JE</I> to a <I>JMP</I> doesn't always work. Sometimes the <I>MSPST32</I> module is unloaded and reloaded into memory (by <I>MSMAPI32</I>) and the modified <I>JE</I> is overwritten.</P><P>I'm sure a memory patcher could be produced that would monitor and correct this automatically, or of course the actual DLL itself could be patched.</P><P>In conclusion, it appears that the PST password security could be relatively easily overcome in Outlook and that any password-protected PSTs cannot necessarily be considered secure.</P></font>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-53283161422687014132007-07-09T21:56:00.000+01:002007-07-09T22:05:51.221+01:00The SSAPI Patcher<span style="font-family:trebuchet ms;">In my first post about SourceSafe, I discussed how SourceSafe security can be bypassed by modifying an instruction in the SSAPI library.</span><br /><br /><span style="font-family:trebuchet ms;">As promised, I have now produced a tool to automate this process.</span><br /><br /><span style="font-family:trebuchet ms;">The tool has the following features:</span><br /><ul><li><span style="font-family:trebuchet ms;">Patches in-memory instances of SSAPI. You can use this if you do not wish to modify an on-disk copy of SSAPI.DLL.</span></li><li><span style="font-family:trebuchet ms;">Patches on-disk instances of SSAPI. This will permanently remove the password protection from SourceSafe on your PC.</span></li></ul><p><span style="font-family:trebuchet ms;">Figure 1 shows a screenshot of the patcher tool.</span></p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTCyTYhkptrDcHg084Wg3cJ0k18e_IiTzktpsl0AcwfkxiXJzgtdf8XoNsP2JHSN9hEbMVIHSGlb27PtFIOo9d6NoA1L6DFNIKKxyXYcbihUNSO5VoG7IECBLfhd174qqxVPsCeS0FPYY/s1600-h/Figure1.GIF"><span style="font-family:trebuchet ms;"><img id="BLOGGER_PHOTO_ID_5085304866729558946" style="CURSOR: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTCyTYhkptrDcHg084Wg3cJ0k18e_IiTzktpsl0AcwfkxiXJzgtdf8XoNsP2JHSN9hEbMVIHSGlb27PtFIOo9d6NoA1L6DFNIKKxyXYcbihUNSO5VoG7IECBLfhd174qqxVPsCeS0FPYY/s400/Figure1.GIF" border="0" /></span></a><br /><p><span style="font-family:trebuchet ms;"></span></p><p><span style="font-family:trebuchet ms;">To patch an in-memory copy of SSAPI, click the Patch Mem button. This will patch all running SourceSafe programs.</span></p><p><span style="font-family:trebuchet ms;">To patch an on-disk copy of SSAPI, click the Patch DLL button. You will need to browse to the DLL that needs patching. A backup copy of the DLL will be made by the program before a patch is made.</span></p><p><span style="font-family:trebuchet ms;">I have rather creatively named the tool the SourceSafe Password Patcher, and it can be downloaded from this location: <a href="http://www.memia.biz/blogs/c2o/sspp.exe">http://www.memia.biz/blogs/c2o/sspp.exe</a>.</span></p><p><span style="font-family:Trebuchet MS;">The tool is written entirely in C# in Microsoft .NET 2.0. I may produce a C++6 version later on for greater compatibility, but only if someone asks for it.</span></p><p><span style="font-family:Trebuchet MS;">If you would like the source code, please ask - but as with the previous tool, you will have much more fun coding a patch yourself from the description in my first SourceSafe article, 'Is SourceSafe "Safe"?'.</span></p><p><span style="font-family:Trebuchet MS;">Enjoy!</span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-40165519437975047822007-07-08T19:57:00.000+01:002007-07-08T20:06:07.987+01:00SourceSafe Password Tool<span style="font-family:verdana;font-size:85%;">Well I had such a lot of fun over my previous articles playing with SourceSafe and seeing what we could do with passwords so I decided to produce a tool which demonstrates all of the previous SourceSafe password articles, with the exception of the SSAPI code patch (I might do that one later).</span><br /><br /><span style="font-family:verdana;font-size:85%;">I've named the tool quite aptly, the SourceSafe Password Cracker, and it provides the following functionality:<br /><br /></span><span style="font-family:verdana;font-size:85%;"><ul><li>Encrypt a password to a coded value</li><li>Attempt to crack a password from a coded value</li><li>Attempt to guess potential password lengths that would produce valid passwords</li><li>Attempt to break a SourceSafe UM.DAT user file</li></ul>Figure 1 contains a screenshot of the main screen:<br /><br /><p align="center"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnT-MSFnjEZ9V69e27Pzqy0fb63qfShN6Jcmp2X6y56gUqUh6l0p_ZP-GQNYwvSAKiIaZDt_Z34hEkiUff3xMCCo6KYkJmS0Ygmb-cVpcajSZ6H-aOnrWlqBk8-nt-p0nXZi-HDtEWuLw/s1600-h/SSPC_MainScreen.GIF"><img id="BLOGGER_PHOTO_ID_5084903373186728850" style="CURSOR: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnT-MSFnjEZ9V69e27Pzqy0fb63qfShN6Jcmp2X6y56gUqUh6l0p_ZP-GQNYwvSAKiIaZDt_Z34hEkiUff3xMCCo6KYkJmS0Ygmb-cVpcajSZ6H-aOnrWlqBk8-nt-p0nXZi-HDtEWuLw/s400/SSPC_MainScreen.GIF" border="0" /></a></p>To Encrypt a Password:<br />Click the "Encrypt password" radio button, and enter the password you want to encrypt in the "Password" text box. Click the Go button and the encrypted password will be shown in the Output box.<br /><br />To Attempt to Crack a Password from a Coded Value:<br />Click the "Crack password" radio button, and enter the coded password in the "Crypto code" text box. Click the Go button and all the potential solutions for that code will be displayed in the Output box.<br /><br />To Guess Password Lengths from a Coded Value:<br />Click the "Guess lengths" radio button, and enter the coded password in the "Crypto code" text box. Click the Go button and all the potential lengths and coded values for the entered code will be displayed in the Output box.<br /><br />To Attempt to Break a SourceSafe UM.DAT User File:<br />Click the "Crack password file" radio button, and click the Go button. On the browse dialog that appears, browse to the file you would like to break and click Open. Any user accounts in the file will be displayed along with potential solutions to the coded passwords.<br /><br />Other Functions:<br /><ul><li>Click the About button to see some information about the tool.</li><li>Click the Clear button to clear the Output box.</li></ul>You can download the file from this location: </span><a href="http://www.memia.biz/blogs/c2o/sspc.exe"><span style="font-family:verdana;font-size:85%;">http://www.memia.biz/blogs/c2o/sspc.exe</span></a>.<br /></span><br /><span style="font-family:verdana;font-size:85%;">Regarding the tool itself, it is a Microsoft .NET 2.0 application written entirely by me in C#. I might produce a .NET 1.1 version of the tool at some point.</span><br /><span style="font-family:Verdana;font-size:85%;"></span><br /><span style="font-family:verdana;font-size:85%;">If you are desparate for the source code, please contact me and I might be able to send it to you, although you will have much more fun writing your own implementation of the articles I published.</span><br /><span style="font-family:verdana;font-size:85%;"></span><br /><span style="font-family:verdana;font-size:85%;">Enjoy!</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-42443653667873947712007-07-07T10:30:00.000+01:002007-07-07T10:38:29.669+01:00Decrypting SourceSafe User List Passwords<div><div><span style="font-family:verdana;font-size:85%;">In my previous article ('SourceSafe Password Decryption' parts one and two) I discussed how to break SourceSafe passwords so that you could gain access to a SourceSafe database even if you didn't have the password for the user. I demonstrated that if you had the encrypted code of the password, you could generate a password that would produce the same code as this.<br /><br />However, what do you do if you don't have the password code? To be honest, unless you had generated one yourself (using my 'SourceSafe Password Encryption' article) it seems unlikely that you would have it.<br /><br />Well the good news is that the password code is stored and is freely available in the SourceSafe file <em>um.dat</em>, which is stored in the <em>data</em> directory under your SourceSafe repository root folder.<br /><br />If you open the file using a hex editor (I recommend a purchased copy of UltraEdit) then you basically see the user database for SourceSafe.<br /><br />If you refer to Figure 1, you will see a hex dump of the start of the file.<br /></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilfToSOPPGU5uPhXC8zmGX0Xv_EehvxcVlNNeZiNd4nfr2eLtNeKPrwARIhU3OI4h0q3xBRYT7NN9_Tm2HBLvbUvIE_1Wf4klgW9XNgpcaANeUo9m7i3lT8GNFt5ElMUtzGqol24RqJ2Y/s1600-h/Figure1.GIF"></a><p align="center"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpp8OJrL5fU3A_TonlWvaUa2mB2VuD9h34rh8h2VwnK_kEeyVployGbmKIlHafWWKOpzc-aJiYkeAWCfHyhWKUdPhMeeu3_47Fb_nUz4w2kDXCih2RAvLIP5ZhTU-QWTihQ-0k_eJBw_0/s1600-h/Figure1.GIF"><img id="BLOGGER_PHOTO_ID_5084386512527360882" style="CURSOR: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpp8OJrL5fU3A_TonlWvaUa2mB2VuD9h34rh8h2VwnK_kEeyVployGbmKIlHafWWKOpzc-aJiYkeAWCfHyhWKUdPhMeeu3_47Fb_nUz4w2kDXCih2RAvLIP5ZhTU-QWTihQ-0k_eJBw_0/s400/Figure1.GIF" border="0" /></a></p><div>The first user account (in this case Admin) begins at offset 0x7C (124), and each user account in 0x40 (64) bytes in length. This means that there must be (file_length - 0x7c) / 0x40 users in each file. In the case of my um.date file, which is 2108 bytes, there are 31 users: (2108 - 124) / 64 = 31.<br /><br />In Figure 1, the user account is highlighted by a green box.<br />Inside the user account, the user name is obvious, at +8 bytes, and the user name can occupy up to 31 bytes.<br />The actual password code is located at +0x28 (40) bytes and is shown in Figure 1 inside a red box. The password code is always 2 bytes in length, so in this case the password for the Admin user is 0x6DAF (28079).<br /><br />Now we have ontained the password code we can decrypt it in accordance with my previous articles. This process can be repeated for each user in the file, if required.</span></div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-50840502089859784572007-07-07T07:30:00.000+01:002007-07-07T10:27:46.516+01:00SourceSafe Password Decryption Part 2<span style="font-family:verdana;font-size:85%;">In my previous article I managed to demonstrate that the password in SourceSafe could be broken if the code for the actual password portion could be obtained.</span><br /><span style="font-family:verdana;font-size:85%;">This is easy if the length of the password is known, but of course this will not be the case most of the time.</span><br /><span style="font-family:verdana;"><br /><span style="font-size:85%;">In order to break the password, we need to ascertain the length of the password portion. I will again consider my admin password 'ADAD', which has been coded (in full) to 0x6DAF (28079).</span><br /><span style="font-size:85%;">I don't know the length of this password though, I just have the full code 28079.</span><br /><span style="font-size:85%;"><br />If I subtract all possible filler codes from this password, I get the following list of values:<br /><br /></span></span><span style="font-family:verdana;"><span style="font-size:85%;"><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="75">Pot Len</td><td align="right" width="130">Filler</td><td align="right" width="130">Remain</td></tr><tr><td align="middle">0</td><td align="right">28304</td><td align="right">-255</td></tr><tr><td align="middle">1</td><td align="right">28012</td><td align="right">67</td></tr><tr><td align="middle">2</td><td align="right">27657</td><td align="right">422</td></tr><tr><td align="middle">3</td><td align="right">27074</td><td align="right">1005</td></tr><tr><td align="middle">4</td><td align="right">25959</td><td align="right">2120</td></tr><tr><td align="middle">5</td><td align="right">24997</td><td align="right">3082</td></tr><tr><td align="middle">6</td><td align="right">23493</td><td align="right">4586</td></tr><tr><td align="middle">7</td><td align="right">21539</td><td align="right">6540</td></tr><tr><td align="middle">8</td><td align="right">19826</td><td align="right">8253</td></tr><tr><td align="middle">9</td><td align="right">17521</td><td align="right">10558</td></tr><tr><td align="middle">10</td><td align="right">15561</td><td align="right">12518</td></tr><tr><td align="middle">11</td><td align="right">12783</td><td align="right">15296</td></tr><tr><td align="middle">12</td><td align="right">9773</td><td align="right">18306</td></tr><tr><td align="middle">13</td><td align="right">6388</td><td align="right">21691</td></tr><tr><td align="middle">14</td><td align="right">3180</td><td align="right">24899</td></tr><tr><td align="middle">15</td><td align="right">0</td><td align="right">28079</td></tr></tbody></table><br /></span><br />Assuming that I don't know that 2120 is the correct code, I need a way of working out which remaining codes are valid. Obviously, 0 isn't valid (-255), so we know this is not a blank password.<br /><br />The answer, as it turns out, is quite straight forward. Basically, if you consider all the characters between 0-9 and A-Z (remember all passwords are converted to upper case), and how they are coded (XOR 0x96), then the lowest possible password code is 160 (0xA0), for '6', and the highest is 223 (0xDF) for 'I'.<br />Now if, at each potential length, we work out the values of the equivalent lengths of '6's and 'I's, as so:<br /><br /><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="75">Pot Len</td><td align="right" width="100">Min (6)</td><td align="right" width="100">Max (I)</td></tr><tr><td align="middle">0</td><td align="right">0</td><td align="right">0</td></tr><tr><td align="middle">1</td><td align="right">160</td><td align="right">223</td></tr><tr><td align="middle">2</td><td align="right">480</td><td align="right">669</td></tr><tr><td align="middle">3</td><td align="right">960</td><td align="right">1338</td></tr><tr><td align="middle">4</td><td align="right">1600</td><td align="right">2230</td></tr><tr><td align="middle">5</td><td align="right">2400</td><td align="right">3345</td></tr><tr><td align="middle">6</td><td align="right">3360</td><td align="right">4683</td></tr><tr><td align="middle">7</td><td align="right">4480</td><td align="right">6244</td></tr><tr><td align="middle">8</td><td align="right">5760</td><td align="right">8028</td></tr><tr><td align="middle">9</td><td align="right">7200</td><td align="right">10035</td></tr><tr><td align="middle">10</td><td align="right">8800</td><td align="right">12265</td></tr><tr><td align="middle">11</td><td align="right">10560</td><td align="right">14718</td></tr><tr><td align="middle">12</td><td align="right">12480</td><td align="right">17394</td></tr><tr><td align="middle">13</td><td align="right">14560</td><td align="right">20293</td></tr><tr><td align="middle">14</td><td align="right">16800</td><td align="right">23415</td></tr><tr><td align="middle">15</td><td align="right">19200</td><td align="right">26760</td></tr></tbody></table><br /></span><br />It becomes clear that for the remaining code to be valid for a length 4 password, it has to fall between the range 1600 ('6666') and 2230 ('IIII').<br /><br />If you consider our remaining codes from our coded password (28079), I have listed the codes that appear to fall within the valid ranges:<br /><br /><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="75">Pot Len</td><td align="right" width="130">Filler</td><td align="right" width="130">Remain</td><td align="middle" width="70">Valid?</td></tr><tr><td align="middle">0</td><td align="right">28304</td><td align="right">-255</td><td align="middle">No</td></tr><tr><td align="middle">1</td><td align="right">28012</td><td align="right">67</td><td align="middle">No</td></tr><tr><td align="middle">2</td><td align="right">27657</td><td align="right">422</td><td align="middle">No</td></tr><tr><td align="middle">3</td><td align="right">27074</td><td align="right">1005</td><td align="middle">Yes</td></tr><tr><td align="middle">4</td><td align="right">25959</td><td align="right">2120</td><td align="middle">Yes</td></tr><tr><td align="middle">5</td><td align="right">24997</td><td align="right">3082</td><td align="middle">Yes</td></tr><tr><td align="middle">6</td><td align="right">23493</td><td align="right">4586</td><td align="middle">Yes</td></tr><tr><td align="middle">7</td><td align="right">21539</td><td align="right">6540</td><td align="middle">No</td></tr><tr><td align="middle">8</td><td align="right">19826</td><td align="right">8253</td><td align="middle">No</td></tr><tr><td align="middle">9</td><td align="right">17521</td><td align="right">10558</td><td align="middle">No</td></tr><tr><td align="middle">10</td><td align="right">15561</td><td align="right">12518</td><td align="middle">No</td></tr><tr><td align="middle">11</td><td align="right">12783</td><td align="right">15296</td><td align="middle">No</td></tr><tr><td align="middle">12</td><td align="right">9773</td><td align="right">18306</td><td align="middle">No</td></tr><tr><td align="middle">13</td><td align="right">6388</td><td align="right">21691</td><td align="middle">No</td></tr><tr><td align="middle">14</td><td align="right">3180</td><td align="right">24899</td><td align="middle">No</td></tr><tr><td align="middle">15</td><td align="right">0</td><td align="right">28079</td><td align="middle">No</td></tr></tbody></table><br /></span><br />Based on the above list, we could actually have a valid password consisting of 3, 4, 5 and 6 characters for the code 28079.<br /><br />From my example in my part one of this post, we know that a 4 character password could be 'KNSB'. There are many other 4 character passwords that would generate a code of 28079.<br /><br />Based upon the above list though, I want to see if I can also generate 3, 5 and 6 character passwords.<br /><br />Working with a 3 character password which has a target code of 1005, if I use the lowest possible password, '666', I get a value of 960, thus:<br /><br /><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="50">Pos</td><td width="130">Char Code</td><td width="150">Code Value</td><td width="150">Total</td></tr><tr><td align="middle">1</td><td>54 (0x36) '6'</td><td>160 * 1</td><td>160</td></tr><tr><td align="middle">2</td><td>54 (0x36) '6'</td><td>160 * 2 = 320</td><td>480 (160 + 320)</td></tr><tr><td align="middle">3</td><td>54 (0x36) '6'</td><td>160 * 3 = 480</td><td>960 (480 + 480)</td></tr></tbody></table><br /></span><br />This is exactly 45 less than our intended target code, 1005.<br />If I add a value of 1 to the character at position 1, this will increase the code by 1.<br />Adding a value of 1 to character position 2 will increase the code by 2, and so on.<br /><br />So to make an additional 45, without causing any of the codes to pass above the maximum ('I', 223), the simplest solution is to add 15 to the coded value of position 3, so change the code value 160 to 175 (which is the coded value of '9'):<br /><br /><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="50">Pos</td><td width="130">Char Code</td><td width="150">Code Value</td><td width="150">Total</td></tr><tr><td align="middle">1</td><td>54 (0x36) '6'</td><td>160 * 1</td><td>160</td></tr><tr><td align="middle">2</td><td>54 (0x36) '6'</td><td>160 * 2 = 320</td><td>480 (160 + 320)</td></tr><tr><td align="middle">3</td><td>57 (0x39) '9'</td><td>175 * 3 = 525</td><td>1005 (480 + 525)</td></tr></tbody></table><br /></span><br />So this means a potential 3 character password could be '669'.<br /><br />Taking this idea and applying it to the 5 and 6 character codes, we get the potential passwords '76PII' and '6XIIII' respectively.<br /><br />I tried all of these in SourceSafe and was immensely pleased to discover that they all worked.<br /><br />This article has demonstrated that it is possible to break SourceSafe passwords, and using the above method I could gain access to a SourceSafe repository using any user account... providing I know the password code.<br />Of course, as I am unlikely to have the code (without using a debugger), I am going to try and find a way to get the codes directly from SourceSafe in my next article...<br /></span></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-42095507960821390192007-07-06T06:00:00.000+01:002007-07-06T23:40:06.430+01:00SourceSafe Password Decryption Part 1<span style="font-family:verdana;font-size:85%;">In my previous article, I set myself the challenge of trying to decrypt the administrator password in SourceSafe. In the article, I worked out and demonstrated how passwords are "encrypted" in SourceSafe.</span><br /><span style="font-family:verdana;font-size:85%;"></span><br /><span style="font-family:verdana;font-size:85%;">Following on from this, I'm going to spend some time trying to work out how they could be decrypted.</span><br /><span style="font-family:verdana;font-size:85%;"><br />To start, refer to the encryption formula again:<br /><span style="font-family:courier new;">Sum (char_position(char XOR 0x96))<br /></span><br />Sadly, I never managed to finish my maths A-level, let alone a degree, so I am not a maths wizard by any means. Trying to figure out a way to reverse this using a simple formula is not proving easy. The best I could come up with was:<br /><span style="font-family:courier new;">n = p1(c1 XOR 150) + p2(c2 XOR 150) + p3(c3 XOR 150)... up to p15(c15 XOR 150)</span><br /><span style="font-family:courier new;">c = char, p = position, n = final result</span><br /><br />Frankly, I have absolutely no idea how to get <em>px</em> or <em>cx</em> when you only have <em>n</em>. I don't even know if it can be reversed (I would guess not without either <em>p</em> or <em>c</em>). Any suggestions are most welcome!<br /><br />So this means that I am not going to be able to decrypt the password - the only choice I have is to break the password.<br /><br />Thinking again about the encryption routine, it is obvious that there are severe weaknesses in the encryption.<br /><br />If we consider that all passwords shorter than 15 characters have filling characters from the string "BrianDavidHarry" appended to them before encryption.<br />If we encrypted the filling characters to calculate their values at each particular password length, we can remove this portion from the coded value of a password to ensure we are only left with the coded portion of the password that represents the actual password, thus:<br /><br /></span><span style="font-family:verdana;font-size:85%;"><span style="font-family:courier new;"><table><tbody><tr><td width="120">Pw Length</td><td width="250">Coded Portion</td><td width="150">Code Value</td></tr><tr><td>0</td><td>BrianDavidHarry</td><td>28304 (0x6E90)</td></tr><tr><td>1</td><td>BrianDavidHarr</td><td>28012 (0x6D6C)</td></tr><tr><td>2</td><td>BrianDavidHar</td><td>27657 (0x6C09)</td></tr><tr><td>3</td><td>BrianDavidHa</td><td>27074 (0x69C2)</td></tr><tr><td>4</td><td>BrianDavidH</td><td>25959 (0x6567)</td></tr><tr><td>5</td><td>BrianDavid</td><td>24997 (0x61A5)</td></tr><tr><td>6</td><td>BrianDavi</td><td>23493 (0x5BC5)</td></tr><tr><td>7</td><td>BrianDav</td><td>21539 (0x5423)</td></tr><tr><td>8</td><td>BrianDa</td><td>19826 (0x4D72)</td></tr><tr><td>9</td><td>BrianD</td><td>17521 (0x4471)</td></tr><tr><td>10</td><td>Brian</td><td>15561 (0x3CC9)</td></tr><tr><td>11</td><td>Bria</td><td>12783 (0x31EF)</td></tr><tr><td>12</td><td>Bri</td><td>9773 (0x262D)</td></tr><tr><td>13</td><td>Br</td><td>6388 (0x18F4)</td></tr><tr><td>14</td><td>B</td><td>3180 (0x0C6C)</td></tr><tr><td>15</td><td></td><td>0 (0x0000)</td></tr></tbody></table><br /></span><br />Consider our current administrator password "adad", which is coded to 0x6DAF (28079). For now, I will assume that I know the length of the password, but not the contents.<br /><br />If I remove the filler coded portion of the password (which will be 25959 for a length 4 password), I am left with a value of 0x0848 (2120).<br /><br />Double checking, I know that this is the correct value by working out how it would be encrypted:<br /><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="50">Pos</td><td width="130">Char Code</td><td width="150">Code Value</td><td width="150">Total</td></tr><tr><td align="middle">1</td><td>65 (0x41) 'A'</td><td>215 * 1</td><td>215</td></tr><tr><td align="middle">2</td><td>68 (0x44) 'D'</td><td>210 * 2 = 420</td><td>635 (215 + 420)</td></tr><tr><td align="middle">3</td><td>65 (0x41) 'A'</td><td>215 * 3 = 645</td><td>1280 (635 + 645)</td></tr><tr><td align="middle">4</td><td>68 (0x44) 'D'</td><td>210 * 4 = 840</td><td>2120 (1280 + 840)</td></tr></tbody></table></span><span style="font-family:courier new;"><br /></span><span style="font-family:courier new;"></span>So I know that 2120 is the correct value of the password portion of the code, but I have no idea what the actual characters are in it.<br /><br />This doesn't actually matter though. I am not trying to decipher the original password, just figure out what I need to type into the login screen in SourceSafe to make it appear that I am typing in that users password.<br />For example, consider what happens if I enter the code 'KSNB':<br /><span style="font-family:courier new;"><table><tbody><tr><td align="middle" width="50">Pos</td><td width="130">Char Code</td><td width="150">Code Value</td><td width="150">Total</td></tr><tr><td align="middle">1</td><td>75 (0x4B) 'K'</td><td>221 * 1</td><td>221</td></tr><tr><td align="middle">2</td><td>83 (0x53) 'S'</td><td>197 * 2 = 394</td><td>615 (221 + 394)</td></tr><tr><td align="middle">3</td><td>78 (0x4E) 'N'</td><td>216 * 3 = 657</td><td>1280 (615 + 657)</td></tr><tr><td align="middle">4</td><td>66 (0x42) 'B'</td><td>212 * 4 = 848</td><td>2120 (1272 + 848)</td></tr></tbody></table></span><br />No way! KSNB is the same password code as ADAD?!<br /><br />Upon brining up SourceSafe Admin and tapping in KSNB I am very pleased to see that I am logged in as administrator.<br /><br />I can even change the password for the admin user, using KSNB as the old password and whatever I feel like as the new one!<br /><br />This is good news, because it means that if I obtain the coded portion of a password, I can work out a sequence of characters that will generate that code and it will code to the the same value as the real password.<br /><br />However, how am I going to obtain the coded portion of a password when I don't know the length of the password?<br /><br />Finding the length of the password is going to prove to be more troublesome, I'm sure...</span> </span>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2220911881289577106.post-50968098931601144912007-07-06T02:00:00.000+01:002007-07-06T23:10:19.852+01:00SourceSafe Password Encryption<span style="font-family:verdana;font-size:85%;">Well it was fun getting administrative access to SourceSafe in my previous article, and if anyone ever forgot their password at least they could gain access to the tool, but it doesn't really provide a full solution because we still haven't got the password for the administrators account.</span><br /><span style="font-family:Verdana;font-size:85%;"></span><br /><span style="font-family:verdana;font-size:85%;">So my next challenge was to see if I could decrypt the administrator password, and to start down this road I needed to work out how the password is encrypted.<br /><br />You might remember from my previous article, 'Is SourceSafe "Safe"', this call in <em>SSAPI</em>:<br /><span style="font-family:courier new;">3DCE6 CALL SSAPI.3E6D0<br /></span><br />And this seemed to take the password off the stack ("Password" in the above case) and set the value of <em>EAX</em> to a number (0x6A10 in this case).</span><br /><span style="font-family:verdana;font-size:85%;"><br />I also notice that the comparison at 3DCEE compares this with the value 0x6DAF (which I assume is the coded version of the password "adad").<br /><br />Well the only reasonable thing to do is see what is happening in the proc at 3E6D0.<br /><br />I won't list the proc here (there's not much point - you can look yourself) but there are a few things to note in it:<br /><ol><li>Whatever password I have entered is converted into upper case (at 3E6F2)</li><li>The password must be 15 characters - if the entered password is shorter then letters from the string "BrianDavidHarry" will be appended to the end (see 3E6F7 to 3F70C). So if I entered "password", this will be changed to "PASSWORDBrianDa"</li><li>If the password is empty, the full string "BrianDavidHarry" will be used</li><li>The appended "BrianDavidHarry" string is not converted to upper case</li></ol><p>So, now we get to 3E714, and this is where the actual codification takes place:<br /><span style="font-family:courier new;">3E714 XOR EAX, EAX<br />-- 3E716 MOVSX DX, BYTE PTR SS:[ESP+EAX+8]<br />/ 3E71C XOR EDX, 0x96<br />/ 3E722 LEA ECX, DWORD PTR DS:[EAS+1]<br />/ 3E725 IMUL EDX, ECX<br />/ 3E728 ADD ESI, EDX<br />/ 3E72A INC EAX<br />/ 3E72B CMP EAX, 0xF<br />-- 3E72E JL SHORT SSAPI.3E716<br /></span><br />So immediately you will see that there is a loop is betwen 3E716 and 3E72E, the counter is stored in <em>EAX</em> and there are 15 steps.</p><p>In 3E716, the next character value is read from the password and stored in <em>DX</em>.</p><p>The character value (in <em>EDX</em>) is the <em>XOR</em>ed with 0x96 (150) although I have no idea why.</p><p>In the next two lines the value in <em>EDX</em> is multiplied by the counter + 1.</p><p>The resulting value in <em>EDX</em> is then added to the value in <em>ESI</em> (which is, of course, 0 at the first loop iteration).</p><p>After we drop out of the loop, we see the value 0x6A10 in <em>ESI</em>, which is moved into <em>EAX</em> before the proc returns... as we expected from the call at 3DCE6!</p><p>So, the password code is encrypted in the following way:<br /><span style="font-family:courier new;">Sum (char_position(char XOR 0x96)) </span><br /><br />In my opinion, hardly a fantastic way of securing the passwords. I know I have used XOR myself in the past to attempt to hide password data, but I wouldn't ever recommend it as a secure way of hiding anything.</p><p>In the case of SourceSafe though, I guess it is sufficient. Or is it...?</span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2220911881289577106.post-53978007650054560462007-07-05T02:15:00.000+01:002007-07-06T22:49:03.213+01:00Is SourceSafe "Safe"?<span style="font-family:verdana;font-size:85%;"><p>For some random reason, which I can't think of right now, I decided it would be fun to see how secure SourceSafe was, and whether access could be gained to the repository without a password. I am using Visual SourceSafe 6.0a (Build 8987) for this article.</p><p>To start with, I thought it would be useful to have a look at the SourceSafe Administration Tool, SSADMIN.EXE, and see if I could gain administrative access to it without having a password.</p><p>First of all, I load <em>OllyDBG</em> and open and run the <i>SSADMIN.EXE</i> application.</p><p>Finding the code that I was interested in was fairly straight forward:</p><ol><li>Entered a garbage password</li><li>Clicked "OK" to attempt to log into the tool</li><li>Saw the "Invalid password" dialogue screen</li><li>Paused execution in <em>OllyDBG</em></li><li>Started debug in "Execute until user code" mode</li><li>Went back to the tool and clicked "OK" on the dialog screen</li><li>Breakpoint triggered in OllyDBG</li></ol><p>It was then a simple case of setting a few breakpoints in different locations and attempting the login procedure a few times.</p><p>Eventually I managed to track down the procedure call to SSAPI where the password I had entered was coded and compared to the stored administrator password (which was coded).</p><p>I found the following code:</p></span><span style="font-family:courier new;">3DCE5 PUSH EAX<br />3DcE6 CALL SSAPI.3E6D0<br />3DCEB ADD ESP, 4<br />3DCEE CMP WORD PTR SS:[ESP+78], AX<br />3DCF3 JE SHORT SSAPI.3DD16<br /></span><span style="font-family:verdana;font-size:85%;"><p> </p><p>The call to a proc at 3DC36 seemed to be where the password was coded, which has been pushed onto the stack from <em>EAX</em>.<br />Stepping over the proc call causes <em>EAX</em> (or specifically <em>AX</em>) to have been changed, in this case to 0x6A10 (which seems to be the coded password).<br />At 3DCEE there is then a comparison between <em>ESP</em>+78 (which contains the value 0x6DAF) and <em>AX</em> (which now contains 0x6A10). These are definitely not equal, of course, so the <em>JE</em> at 3DCF3 is not taken and the result is that the "Invalid Password" dialog is displayed.</p><p>So, what will happen if which force the <em>JE</em> at 3DCF3 to be taken - surely this wouldn't be enough for the user to be allowed administrative access to the tool...?</p><p>Setting a breakpoint at 3DCF3, I re-enter the wrong password and am taken back to OllyDBG where the breakpoint has triggered, and again the jump will not be taken, which is quickly rectified by modifying the <em>Z</em> register to on (1), and now the jump will be taken.</p><p>I continue running the program, and now have full access to the tool!</p><p>So it turns out that gaining access to the SourceSafe Administration tool wasn't that difficult after all. The code portion in SSAPI is also used by SourceSafe itself too, so I can gain access to the repository using the same method.</p><p>Now all that remains is to decide whether to write an in-memory patcher for SSAPI or whether to permanently patch the SSAPI.dll...</p></span>Unknownnoreply@blogger.com2