[转]Replace all UUIDs in an ATL COM DLL.

1. Introduction.

1.1 Recently, a friend asked me for advise on a very unusual requirement.

1.2 He needs to replace all UUIDs in a COM DLL with new ones.

1.3 He does not have the source codes to the original COM server so any modifications will have to be done on the binary code.

1.4 To be more accurate, the objective was to replace the UUIDs of COM Types defined in the COM DLL.

1.5 Ever enthusiastic for any opportunity to do unusual spelunking, I helped to research into this.

1.6 Using a sample COM in-proc server written in ATL, I managed to accomplish this and verified the results using a test program.

1.7 In this blog, I aim to demonstrate to the reader how this can be done.

2. The General Outline of the Plan.

2.1 As I advised my friend, performing such a feat is certainly possible but it depends on how the original COM DLL was created :

– What tool was used to create the DLL ? e.g. ATL, VB, C#, etc.
– Was it hand-crafted instead in C++ ?

2.2 Assuming that the COM DLL server was developed using ATL, the process is quite straightforward but involves a number of steps :

  • Replacing the Type Library embedded as a resource inside the DLL.
  • Replacing the registration strings embedded as a resource inside the DLL.
  • Replacing all occurrences of specific GUIDs inside the code of the DLL.
  • Registering the new DLL.

2.3 For the purposes of demonstration, I created a simple COM in-proc server and a test console application that uses the COM Types in the DLL.

2.4 The test program will initially link with the original DLL.

2.5 After we have created a new DLL with all the replacement UUIDs, the test program will link to the new DLL and we shall see that the output of the test program will be the same.

3. A Simple ATL COM DLL.

3.1 The following are the main characteristics of the COM DLL (SimpleATLCOMServer.dll) which we will be working on :

  • It is 32-bit and is written using ATL.
  • It exposes a single coclass named SimpleCOMClass.
  • SimpleCOMClass exposes a single interface ISimpleCOMClass.
  • SimpleCOMClass supports a COM event _ISimpleCOMClassEvents.

3.2 The following is a listing of the IDL :

 
 

3.3 The ISimpleCOMClass interface has a single method TestMethod01() which takes a BSTR as parameter.

3.4 The _ISimpleCOMClassEvents event interface has a single method TestEvent01() which also takes a BSTR parameter.

3.5 The actual implementation for ISimpleCOMClass is a C++ class named CSimpleCOMClass.

3.6 The definition for TestMethod01() is as follows :

 
 

It displays the contents of the BSTR parameter and then fires TestEvent01() using the same BSTR parameter to TestMethod01().

3.7 In the sections that follow, we will expound in greater detail the steps that we take to replace all COM UUIDs in the DLL with new ones.

4. Replacing the Type Library embedded as a resource inside the DLL.

4.1 Extracting the type library of the original DLL can be done using OleView. The following is a screenshot of how the IDL will be displayed :

simpleatlcomserver-idl

  • The great thing about OleView is that it is able to save the displayed IDL into an external file.
  • We shall save it as SimpleATLCOMServerNew.IDL.

4.2 Next, open SimpleATLCOMServerNew.IDL and perform the following changes :

  • Generate new UUIDs using GUIDGEN.EXE.
  • Replace the UUID for the SimpleATLCOMServerLib LIBID, _ISimpleCOMClassEvents Event Interface UUID, the SimpleCOMClass coclass CLSID and ISimpleCOMClass interface IID.
  • Change the name of the library from SimpleATLCOMServerLib to SimpleATLCOMServerNewLib.

The following is a sample modified SimpleATLCOMServerNew.IDL :

 
 

All new replacement UUIDs are displayed in bold. The new name for the library is also in bold.

4.3 Next we need to recompile the new IDL using MIDL.exe :

  • In a command prompt, go to the folder where SimpleATLCOMServerNew.IDL is stored and run the following command :
 
 
  • Before running this command, you may need to set the “INCLUDE” path to include new directories (so as to ensure a successful MIDL compilation) :
 
 
  • A new type library SimpleATLCOMServerNew.tlb will be produced.

4.4 Then, use Visual Studio to replace the original type library of the DLL with the new modified one :

  • Make a copy of the original SimpleATLCOMServer.dll and named it as SimpleATLCOMServerNew.dll.
  • Run Visual Studio and open SimpleATLCOMServerNew.dll as an executable file.

open-simpleatlcomservernew-dll-as-executable

  • Right-click on “TYPELIB” and select “Add Resource” :

typelib-addresource

  • The “Add Resource” dialog box will appear :

addresourcedlg

  • Select “TYPELIB” and click on the “Import” button.
  • A File Selection dialog box will appear.
  • Search for and select the new type library SimpleATLCOMServerNew.tlb that we have just created.
  • A new “TYPELIB” resource will be added :

typelib-newresource

  • Note well, however, that the resource ID for the new “TYPELIB” resource is one given by Visual Studio.
  • In our example, it is 101. It needs to be renumbered to 1.
  • To do this, remove the “TYPELIB” resource with ID 1 by righ-clicking on it and selecting “Delete” :

typelib-deleteresource

  • Thereafter, select the 101 resource and right-click on it. Then select “Properties”.
  • Under the “Properties” explorer, change the ID to 1 :

typelib-changeresourceid

  • And that’s it. We have put in place a new type library resource within the COM DLL.

5. Replacing the Registration Scripts Embedded as a Resource inside the DLL.

5.1 The registration scripts are the .rgs resources commonly found in ATL projects.

5.2 It contains strings that are used in the COM registration process.

5.3 The objective is to extract the existing .rgs resources, modify them, and then re-insert them into the DLL.

5.4 Extracting the .rgs resource is done once again using Visual Studio by opening up the DLL as an executable file :

  • This time, the .rgs resources are contained in “REGISTRY” :

registry-extractresource

  • Unlike the type library, there could be several .rgs resources contained in “REGISTRY”.
  • However, in our simple example, only one .rgs resource is important (ID 106).
  • Select all relevant ,rgs resources and export them by right-clicking and then selecting “Export” :

registry-exportresource

  • A File-Save dialog box will appear. Save it as SimpleATLCOMServerNew.rgs.
  • SimpleATLCOMServerNew.rgs is a text file. Open it using notepad.exe.
  • The following is the contents :
 
 
  • We need to replace the existing UUIDs with new corresponding ones :
 
 
  • Next, using methods that we have used previously on type library replacement, replace the existing “REGISTRY” resource (ID 106) with the new modified one.

6. Replacing all Occurrences of Specific UUIDs inside the Code of the DLL.

6.1 This is by far the most interesting part of the replacement process.

6.2 To do this, we need to write a program that performs the following :

  • Open the DLL file as a stream of bytes.
  • Scan through the stream of bytes and search for byte patterns that correspond with the original UUIDs.
  • Replace all original UUIDs with the new ones.

6.3 It is important to note that a UUID is in actual fact a binary structure and not a string (see UUID structure).

  • For convenience, UUIDs are often represented as strings in source codes.
  • But they will all resolve to binary structures at runtime.
  • Code like the following :
 
 

requires that IID_ISimpleCOMClass be expressed as a structure like the following :

 
 
  • It is essentially a series of bytes.
  • Hence to replace all occurrences of IID_ISimpleCOMClass in a DLL, our program can simply search for such byte sequences and directly replace them.

6.4 This program is best done in C# due to the rich functionality of the .NET class libraries.

6.5 The following is a listing of the C# program :

 
 
  • Note that the code for the Replace() method is taken directly from the following StackOverflow discussion thread :

Most efficient way to replace one sequence of the bytes with some other sequence.

6.6 The program expects 4 runtime arguments :

  • The path to the original DLL.
  • The path to the a new DLL that will contain the replaced UUID.
  • The original UUID in string form.
  • The replacement UUID in string form.

The following is a sample command line :

  • The above command will change all occurrences of the original IID of ISimpleCOMClass with a new one that we have generated.
  • A new DLL SimpleATLCOMServerNew.01.dll will be created with the new IID.
  • We will have to call ConsoleGUIDReplacer.exe 4 times in order to replace all original UUIDs with the new ones.
  • Each time we run ConsoleGUIDReplacer.exe, a new version of the SimpleATLCOMServerNew DLL will be generated.
  • Eventually, we will emerge with a complete SimpleATLCOMServerNew.dll with all original UUIDs replaced with new ones.

6.7 The availability of structures like Guid in .NET goes a long way towards simplifying things :

  • It provides a constructor that takes a UUID in string form (perfect for us).
  • It provides a ToByteArray() method that simplifies the process of expressing the UUID as a series of bytes (again, perfect for us).

7. Registering the new DLL.

7.1 Not to forget : we must also register the new SimpleATLCOMServerNew.dll.

7.2 This is necessary because it is, in the eyes of COM, completely distinct from the original SimpleATLCOMServer.dll.

7.3 Run regsvr32.exe as per normal.

8. Test Program.

8.1 The following is a general game plan for the test :

  • We write a C++ console program that imports the original SimpleATLCOMServer.dll.
  • In the test program, we will create an instance of the SimpleCOMClass coclass.
  • Using its ISimpleCOMClass interface, we call TestMethod01().
  • We will also write an event handler class and receive the TestEvent01() event.
  • We then modify the test program and import the new SimpleATLCOMServerNew.dll.
  • We then re-compile and run the program once again.
  • The same result will be observed.

8.2 The listing for the test program is as follows :

 
 

8.3 For the purposes of the test, I have copied the original and new DLLs into the same folder as the project of the test program.

8.4 Notice that when we import SimpleATLCOMServerNew.dll, we use the SimpleATLCOMServerNewLib namespace.

8.5 This is because of what we did in point 4.2 where we changed the name of the library statement in the new IDL from SimpleATLCOMServerLib to SimpleATLCOMServerNewLib.

8.6 For handling COM events, I have created the EventHandler class and have used the TEventHandler class (see Understanding COM Event Handling) to simplify handling IDispatch-based event interfaces.

8.7 When we run the above code, the following will occur :

  • As TestMethod01() is called, the following dialog box will be displayed :

testprogram01

  • Then TestMethod01() will fire the TestEvent01() event which will cause our event handler to display the following dialog box :

testprogram02

8.8 Next, comment out the import of the SimpleATLCOMServer.dll and comment in the import of SimpleATLCOMServerNew.dll :

 
 
  • Re-compile the test program.
  • Run it again.

You will see that the same dialog boxes will be displayed.

8.9 As an additional step that we can take to ensure that these 2 DLLs are truly distinct, we can modify the original SimpleATLCOMServer.dllby changing the code for TestMethod01() as follows :

 
 

We simply change the dialog box title to “CSimpleCOMClass Original”.

8.10 Thereafter, modify ConsoleClientApp.cpp once again to import SimpleATLCOMServer.dll, compile the test program and run it :

  • This time, when TestMethod01() is called, the following will be displayed :

testprogram-change-original

8.11 Now, once again import SimpleATLCOMServerNew.dll, re-compile and run the program :

  • When TestMethod01() is called, the original dialog box will be displayed :

testprogram01

9. In Summary.

9.1 In summary, we can see that complete replacement of UUIDs in a COM DLL server is possible. However, note well :

  • As mentioned previously, we are merely changing the UUIDs of COM types which have already been implemented in the server.
  • We are not attempting to change the logic of the implementation code.
  • If the implementation code references other CLSIDs, IIDs, LIBIDs or any other UUIDs other than the ones we already know, we do not modify these (in fact, we shouldn’t).

9.2 Note well that, with the exception of COM servers written in a managed language, regardless of whatever tool was used to generate a COM DLL server, the following are common requirements of the DLL :

  • All COM DLLs must have its type library embedded as a resource. This is to ensure that the COM types in the DLL can be referenced by development tools like Visual Studio (e.g. via the #import statement in C++).
  • All COM DLLs (whatever tool was used to create it), must be self-registrable.

Hence at minimum, it should be no problem to at least modify the embedded type libraries contained inside a COM DLL. Modifying the self-registration code will require some further research.

9.3 The techniques for modification of UUIDs in runtime code will also likely be varied.

9.4 I hope to research into these in the future.

10. Source Codes.

10.1 The source codes for this blog can be downloaded from here.

转载于:https://www.cnblogs.com/czytcn/p/7928173.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值