DLL hijacking involves manipulating a program to load a DLL that contains the desired code. We will use a simple technique here for ilustration: DLL replacement. We will build a DLL that perserve the same functionlity and interface of original DLL. So we can swap the original DLL with a the one built by us that contains additional code.

Assuming the vulnerable program has dependency on zlib1.dll, which is the open source library. We can first check the version from file properties and download the corresponding version of source code for example zlib v1.2.1.

Execute cd into source source folder and then execute nmake -f win32/Makefile.msc, we will obtain zlib.lib, zlib1.res. We can now build our zlib1.dll. Put our source code zlib1.c with additional instantiation logic and copy zlib.lib, zlib1.res, zlib.def into the same folder and then execute following commands

cl /c /nologo /O2 /MD /utf-8 zlib1.c
link /NOLOGO /RELEASE /DEF:zlib.def /DLL /IMPLIB:zdll.lib /OUT:zlib1.dll zlib1.obj zlib.lib zlib1.res User32.lib Gdi32.lib

In case we don’t have module-definition or .def file then we will need to modify the source code of our proxy DLL zlib1.c. We need to first execute dumpbin /EXPORTS zlib1.dll so we will obtain the export table of original zlib1.dll. The output should be something similar to following:

      1    0 00001000 adler32
      2    1 000011E0 compress
      3    2 00001130 compress2
      4    3 00001200 compressBound
      5    4 00001510 crc32
      6    5 00001760 deflate
      7    6 00001680 deflateBound
      8    7 00001C60 deflateCopy
      9    8 00001BA0 deflateEnd
     10    9 00003050 deflateInit2_
     11    A 00003280 deflateInit_
     12    B 00002CC0 deflateParams
     13    C 00001640 deflatePrime
     14    D 00002C20 deflateReset
     15    E 00001530 deflateSetDictionary
     16    F 00001220 get_crc_table
     17   10 00003B20 gzclearerr
     18   11 000039D0 gzclose
     19   12 00003DC0 gzdopen
     20   13 00003930 gzeof
     21   14 00003A20 gzerror
     22   15 00003880 gzflush
     23   16 000040B0 gzgetc
     24   17 000040E0 gzgets
     25   18 00003DA0 gzopen
     26   19 000036C0 gzprintf
     27   1A 00003740 gzputc
     28   1B 00003770 gzputs
     29   1C 00003E00 gzread
     30   1D 000038C0 gzrewind
     31   1E 00004140 gzseek
     32   1F 000032B0 gzsetparams
     33   20 000042E0 gztell
     34   21 000035A0 gzungetc
     35   22 000035F0 gzwrite
     36   23 00005950 inflate
     37   24 000043C0 inflateBack
     38   25 00005240 inflateBackEnd
     39   26 00004300 inflateBackInit_
     40   27 00007060 inflateCopy
     41   28 00006DB0 inflateEnd
     42   29 00005740 inflateInit2_
     43   2A 00005810 inflateInit_
     44   2B 000056F0 inflateReset
     45   2C 00006E00 inflateSetDictionary
     46   2D 00006F30 inflateSync
     47   2E 00007030 inflateSyncPoint
     48   2F 00009050 uncompress
     49   30 00009120 zError
     50   31 00009110 zlibCompileFlags
     51   32 00009100 zlibVersion

for every export attribute we will need a add a line to our zlib1.c

#pragma comment(linker, "/export:_<export attribute>")

for example

#pragma comment(linker, "/export:_zlibVersion")

We place generated zlib1.dll into program directory and replace the original one, our logic will be executed when program try to load zlib1.dll.

Alternatively for any other DLL even it is not open source, we can build a proxy DLL that redirect all the calls to original DLL file. There are automatic tool for generating the proxy DLL.

Reference