Extract data from .dat files of an old delphi application

Sure! Here’s the updated translation with your additional information included:


Hello everyone,

I’m a senior JS+PHP developer, but I have no experience with Delphi or Data Abstract. I have an old application in my company, around 16 years old, that has been abandoned (the original developer is no longer available, and we transitioned to new technologies some time ago, which I now manage). I’m trying to retrieve data from this program, but it’s quite challenging. The application was a legacy platform used to make reservations for certain services for our clients. It didn’t have an installer; instead, it was a single client.exe file that, once launched, generated .dat files in the same folder as the executable. These .dat files aren’t plain text and seem to represent database tables (like cities.exe, customers.exe, and so on), which sync with a database located on the same network. I assume that back then, there wasn’t a request/response protocol but rather a data synchronization process between the client and server.

My goal is to be able to read these .dat files somehow. I used a tool called PE Explorer on the client.exe file and gathered several pieces of information, including that the software was developed in Delphi and accesses the data through the Data Abstract for Delphi method Bin2DataStreamer. I assume that these .dat files are serialized using this method. Through PE Explorer, I can also see the structure of the data, for example, the Cities table has fields like ID, Description, and Language ID.

Now, I’d like to attempt data retrieval, and I noticed that there are Data Abstract libraries for JS, which also include the Bin2DataStreamer method. However, I can’t find a starting point to write the code because it seems that Bin2DataStreamer requires a stream/endpoint to function, and I can’t directly pass it a file. Of course, I could access the client since I have the passwords, but extracting this data manually is impossible, and the software doesn’t have an export system. I’m looking for any advice on how to start this reverse engineering process. Unfortunately, the local database isn’t accessible because it’s running on a VM I don’t have physical access to, so I’m trying to recover the data directly from the client.

Thanks.

Hi,

Can you specify the first 8 bytes (aka signature) of .dat file, pls?

Bin2 file should have DABIN200 signature

Dear thank you for the reply, this is a dump of a file named Cities.dat

F1 F4 45 0B F3 FA 98 80 96 E1 8F 75 9F 2C 27 9C   ñôE.óú˜€–á.uŸ,'œ
71 79 E0 6B 60 B9 45 A3 8C 63 75 88 AC 57 81 8A   qyàk`¹E£Œcuˆ¬W.Š
EB BC 56 45 A2 9B 5B 13 2F 1D 6A 69 47 F4 08 5E   ë¼VE¢›[./.jiGô.^
CC 29 A7 33 A0 A7 49 9D B6 CB 73 D5 5F B7 43 4D   Ì)§3 §I.¶ËsÕ_·CM
82 05 23 49 5B 37 7D 02 E7 BD 85 87 D9 57 E9 6B   ‚.#I[7}.ç½…‡ÙWék
79 71 68 3F FD 7E CB BD 03 C9 DA E2 CA B5 DD B9   yqh?ý~˽.ÉÚâʵݹ

As you pointed I cannot see any readable header or meta data, could it be there is some kind of compression around this? I’m pretty sure that the .dat are stored with Bin2DataStreamer beacuse of this part of Delphi code I found where the structure of cities is declared, that seems to relies to DataStreamer = ClientDataModule.DataStreamer for serialization/streaming procedures:

// <DFM>  TDTMCACHECLIENT = class(TForm);

object dtmCacheClient: TdtmCacheClient
  OldCreateOrder = False
  OnCreate = DataModuleCreate
  OnDestroy = DataModuleDestroy
  Height = 746
  Width = 1015
  object cdsBookingType: TDAMemDataTable
    Tag = 2
    Fields = <
      item
        Name = 'ID'
        DataType = datAutoInc
        GeneratorName = 'dbo.BookingType'
        Required = True
        InPrimaryKey = True
      end
      item
        Name = 'Code'
        DataType = datString
        Size = 5
        Required = True
      end
      item
        Name = 'DefaultDescr'
        DataType = datString
        Size = 50
        Required = True
      end
      item
        Name = 'SwActive'
        DataType = datInteger
      end
      item
        Name = 'SortID'
        DataType = datInteger
      end
      item
        Name = 'BookingTypeUID'
        DataType = datInteger
      end
      item
        Name = 'BookingColor'
        DataType = datInteger
      end>
    LogicalName = 'BookingType'
    Params = <>
    RemoteDataAdapter = CacheRemoteDataAdapter
    RemoteUpdatesOptions = []
    StreamingOptions = [soDisableEventsWhileStreaming, soDisableFiltering]
    IndexDefs = <>
    Left = 40
    Top = 24
  end
  object CacheRemoteDataAdapter: TDARemoteDataAdapter
    GetSchemaCall.RemoteService = CaCheRemoteService
    GetDataCall.RemoteService = CaCheRemoteService
    UpdateDataCall.RemoteService = CaCheRemoteService
    GetScriptsCall.RemoteService = CaCheRemoteService
    RemoteService = CaCheRemoteService
    DataStreamer = ClientDataModule.DataStreamer
    Left = 760
    Top = 24
  end
  object CaCheRemoteService: TRORemoteService
    ServiceName = 'CachService'
    Channel = ClientDataModule.ClientChannel
    Message = ClientDataModule.Message
    Left = 760
    Top = 80
  end

  object cdsCities: TDAMemDataTable
    Tag = 2
    Fields = <
      item
        Name = 'id'
        DataType = datAutoInc
      end
      item
        Name = 'descr'
        DataType = datString
        Size = 50
      end
      item
        Name = 'langid'
        DataType = datInteger
      end>
    LogicalName = 'Cities'
    Params = <>
    RemoteDataAdapter = CacheRemoteDataAdapter
    RemoteUpdatesOptions = []
    StreamingOptions = [soDisableEventsWhileStreaming, soDisableFiltering]
    IndexDefs = <>
    Left = 624
    Top = 80
  end
// <DFM>  TCLIENTDATAMODULE = class(TForm);

object ClientDataModule: TClientDataModule
  OldCreateOrder = True
  OnCreate = DataModuleCreate
  OnDestroy = DataModuleDestroy
  Height = 659
  Width = 1170
  object ClientChannel: TROSuperTCPChannel
    RequestTimeout = 600000
    StoreActive = False
    SynchronizeEvents = True
    DispatchOptions = []
    OnLoginNeeded = ClientChannel_OnLoginNeeded
    ServerLocators = <>
    TargetUrl = 'supertcp://localhost:8095'
    Host = 'localhost'
    Left = 24
    Top = 8
  end
  object Message: TROBinMessage
    Envelopes = <>
    Left = 88
    Top = 8
  end
  object RemoteService: TRORemoteService
    ServiceName = 'DataService'
    Channel = ClientChannel
    Message = Message
    Left = 256
    Top = 72
  end
  object DataStreamer: TDABin2DataStreamer
    Left = 160
    Top = 8
  end
  object RemoteDataAdapter: TDARemoteDataAdapter
    GetSchemaCall.RemoteService = RemoteService
    GetDataCall.RemoteService = RemoteService
    GetDataCall.MethodName = 'GetData'
    GetDataCall.Params = <
      item
        Name = 'Result'
        DataType = rtBinary
        Flag = fResult
        Value = Null
      end
      item
        Name = 'aTableNameArray'
        DataType = rtUserDefined
        Flag = fIn
        TypeName = 'StringArray'
        Value = Null
      end
      item
        Name = 'aTableRequestInfoArray'
        DataType = rtUserDefined
        Flag = fIn
        TypeName = 'TableRequestInfoArray'
        Value = Null
      end>
    GetDataCall.Default = False
    GetDataCall.OutgoingTableNamesParameter = 'aTableNameArray'
    GetDataCall.OutgoingTableRequestInfosParameter = 'aTableRequestInfoArray'
    GetDataCall.IncomingDataParameter = 'Result'
    UpdateDataCall.RemoteService = RemoteService
    GetScriptsCall.RemoteService = RemoteService
    RemoteService = RemoteService
    CacheSchema = True
    DataStreamer = DataStreamer
    Left = 256
    Top = 8
  end
  object GeneralDataServiceRemote: TRORemoteService
    ServiceName = 'GeneralDataService'
    Channel = ClientChannel
    Message = Message
    Left = 376
    Top = 72
  end
  object GeneralRemoteAdaptor: TDARemoteDataAdapter
    DynamicSelect = True
    GetSchemaCall.RemoteService = GeneralDataServiceRemote
    GetDataCall.RemoteService = GeneralDataServiceRemote
    GetDataCall.MethodName = 'GetData'
    GetDataCall.Params = <
      item
        Name = 'aTableNameArray'
        DataType = rtUserDefined
        Flag = fIn
        TypeName = 'StringArray'
      end
      item
        Name = 'aTableRequestInfoArray'
        DataType = rtUserDefined
        Flag = fIn
        TypeName = 'TableRequestInfoArray'
      end
      item
        Name = 'Result'
        DataType = rtBinary
        Flag = fResult
      end>
    GetDataCall.Default = False
    GetDataCall.OutgoingTableNamesParameter = 'aTableNameArray'
    GetDataCall.OutgoingTableRequestInfosParameter = 'aTableRequestInfoArray'
    GetDataCall.IncomingDataParameter = 'Result'
    UpdateDataCall.RemoteService = GeneralDataServiceRemote
    GetScriptsCall.RemoteService = GeneralDataServiceRemote
    RemoteService = GeneralDataServiceRemote
    DataStreamer = DataStreamer
    Left = 376
    Top = 8
  end

Hi,

this dump isn’t related to any known formats of ROD/DAD:

this is data in unknown (from ROD/DAD sight) format.
We can’t help with it.

note: all our binary formats have signature at the beginning of file like

  • DABINxxx
  • RO107
  • ROENV
  • roroc

Dear thank you, since I can clearly see in the code I posted the DataStreamer: TDABin2DataStreamer, could it be that there is a further compression or encryption method that I cannot see after using DA Streamer?

Hi,

it can be user-defined compression/encryption that isn’t related to ROD/DAD.

1 Like

Dear sorry again,
I understand that must be some kind of encryption on the local tables, but following tcpdump flow I can view R0107 and DABIN200 data, like the below request for availability, pheraps I could try to make a huge query in the application and decode the tcpdump using the js framework. If you could just give to me a starting point to accomplish this, I know is not the best way but at least I could fetch some data.

many thanks

REQUEST

02 ca 00 00 00                                     .....
01 cb 00 00 00 6c 00 00  00 52 4f 31 30 37 00 00   .....l.. .RO107..
00 00 00 00 00 5a 66 26  0d 9d 80 34 49 a9 10 5a   .....Zf& ...4I..Z
29 a9 3d 1b c4 0d 00 00  00 52 65 70 6f 72 74 53   ).=..... .ReportS
65 72 76 69 63 65 0f 00  00 00 47 65 74 41 76 61   ervice.. ..GetAva
69 6c 61 62 69 6c 69 74  79 01 00 00 00 00 00 00   ilabilit y.......
00 00 00 00 00 4c 09 00  00 13 03 00 00 02 00 00   .....L.. ........
00 02 0e 02 00 63 c3 11  00 01 00 00 00 00 00 00   .....c.. ........
00 01 00 00 00                                     .....

RESPONSE

02 cb 00 00 00                                     .....
01 cb 00 00 00 04 0d 00  00 52 4f 31 30 37 01 00   ........ .RO107..
00 00 00 00 00 5a 66 26  0d 9d 80 34 49 a9 10 5a   .....Zf& ...4I..Z
29 a9 3d 1b c4 78 9c ed  9d 4f 6c 1c 57 1d c7 c7   ).=..x.. .Ol.W...
89 ed f8 4f 1c db 49 49  9a 52 e8 52 4a 5b 20 a1   ...O..II .R.RJ[ .
5e ff 4f 5b 24 af bd 76  6a 70 6c cb bb 29 54 1c   ^.O[$..v jpl..)T.
92 f1 7a e2 8c 32 de 35  b3 b3 49 cc 01 59 ca 91   ..z..2.5 ..I..Y..
0b 47 0e 1c 72 e6 c0 05  89 0b 42 58 04 24 a8 28   .G..r... ..BX.$.(
6d 45 38 f4 40 c5 09 09  2e 54 e2 08 a8 bc df cc   mE8.@... .T......
7b 33 6f de fe e6 ed 68  76 97 71 26 ef 27 6d 7e   {3o....h v.q&.'m~
99 37 9e 37 33 9f f7 fd  bd 7f f3 76 76 44 d3 b4   .7.73... ...vvD..
2d 63 bf 66 3b 25 c3 be  6b 56 8c 0b 24 e1 aa e1   -c.f;%.. kV..$...
14 ee ea a6 a5 6f 9b 96  e9 1c 6c 19 f5 fd 5a b5   .....o.. ..l...Z.
6e f4 6c ff 51 d3 8a 85  c5 d5 f5 c9 89 89 ab e4   n.l.Q... ........
ff 9f be ff 40 d3 2e 91  03 5e 24 9f 41 f2 29 58   ....@... .^$.A.)X
e6 6e 75 cf a8 3a 23 64  c3 d1 d7 8c 5b ce 37 1a   .nu..:#d ....[.7.
75 c7 bc 75 30 40 12 16  ad da 76 f9 60 df 18 26   u..u0@.. ..v.`..&
ff df d1 b7 9d eb d5 3b  d5 da bd ea 28 ec 6a d4   .......; ....(.j.
cd aa 51 af 2f 59 7a bd  be 5a 24 29 da 10 f9 2c   ..Q./Yz. .Z$)...,
e9 56 a5 61 e9 8e b1 d3  47 b6 56 74 ab 6e 8c 41   .V.a.... G.Vt.n.A
32 c9 b3 b6 57 70 1c db  dc 6e 38 46 1d fe 1c 4e   2...Wp.. .n8F...N
71 4a f9 98 f2 9b 28 29  ed 67 40 fb 63 41 a9 ae   qJ....() .g@.cA..

Hi,

you can read ROBinHeader and TDAMemDataTable using TDABin2DataStreamer (Delphi) articles.

by other hand, you can review sources (Delphi or .NET) that read and write these formats.