News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

SFX CAB archive made easy

Started by jdoe, July 11, 2008, 11:41:30 PM

Previous topic - Next topic

jdoe


These are the steps the build a program known as SFX EXE.


1) Make a Cabinet archive of the files you want. The archive can include relative folder path. You can find programs on the Web to build the Cabinet or you can use my old one called "CAB Tool" but it only works on Windows 2000/XP/2003 (it use the SendTo menu... right-click on the folder and send it to "CAB Tool" and the content will be added to a Cabinet archive of the same name as the folder).


2) In your resource file, add a line like below and FILE.CAB will be the name of the resource in your program and the name of the Cabinet archive file (for easier handling in your program).

FILE.CAB RT_RCDATA "FILE.CAB"


3) Your program can do whatever you want but the interesting part is when the files are extracted. We'll use the SetupIterateCabinet Win32 API for that task. All error handling are removed for an easier reading of the concept.

Get the Cabinet resource pointer.


    invoke FindResource, hInstance, addr szCabName, RT_RCDATA
    mov hResInfo, eax
    invoke LoadResource, hInstance, hResInfo
    mov hResData, eax
    invoke SizeofResource, hInstance, hResInfo
    mov dwResSize, eax
    invoke LockResource, hResData
    mov lpResData, eax


Write the resource to disk, in the TEMP folder in this example.


    invoke GetTempPath, MAX_PATH, addr szCabPath
    invoke lstrcat, addr szCabPath, addr szCabName
    invoke CreateFile, addr szCabPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, NULL, NULL
    mov hCabFile, eax
    invoke WriteFile, hCabFile, lpResData, dwResSize, addr dwBytesWritten, NULL
    invoke CloseHandle, hCabFile


Now we call SetupIterateCabinet.


    invoke PathAddBackslash, addr szInstallPath
    invoke SetupIterateCabinet, addr szCabPath, NULL, addr FileCallback, addr szInstallPath


The callback function looks like this (take note that CreateFolder is custom function that needs to be able to create all intermediate folders).


FileCallback PROC Context:DWORD, Notification:DWORD, Param1:DWORD, Param2:DWORD

    LOCAL szMaxPath[MAX_PATH]:BYTE

    .if (Notification == SPFILENOTIFY_FILEINCABINET)

        push edi

        mov edi, Param1

        invoke lstrcpy, addr [edi].FILE_IN_CABINET_INFO.FullTargetName, p_Context
        invoke lstrcat, addr [edi].FILE_IN_CABINET_INFO.FullTargetName, [edi].FILE_IN_CABINET_INFO.NameInCabinet

        invoke lstrcpy, addr szMaxPath, addr [edi].FILE_IN_CABINET_INFO.FullTargetName
        invoke PathRemoveFileSpec, addr szMaxPath
        invoke CreateFolder, addr szMaxPath

        pop edi

        mov eax, FILEOP_DOIT

    .else

        mov eax, NO_ERROR

    .endif

    ret

FileCallback ENDP



4) After all that, your program will be recognize as an SFX CAB archive by almost all of the popular programs like WinZip or WinRAR. It means that your program won't need to executed for the file to be extracted. WinZip or WinRAR are going to be able to extract the files.


That was not an exhaustive tutorial but feel free to post questions if you need more informations.


lingo


jdoe

Quote from: lingo on July 12, 2008, 10:55:38 AM
Virus in attached file...

Thanks for reporting lingo.

I'm not really sure that it is a false detection but I removed all PE files from my web site. Some of the files on my site were there since long time ago and I can't be sure that my site was hacked or not. I've changed my ftp password and will upload new compiled files soon.

I am sorry for any inconvenience.

:(


Vortex

Hi jdoe,

Nice project. Why not to convert the cab module to a MS COFF object file which can be linked with the main project module?

evlncrn8

linking the cab stuff as resources is impractical if the file is huge as it will most likely fail on loading, or the exe failing to load due to there being not enough system resources...
storing the cab file as appended data is a better approach for large cab files...

jdoe

Quote from: evlncrn8 on July 13, 2008, 10:34:14 AM
linking the cab stuff as resources is impractical if the file is huge as it will most likely fail on loading, or the exe failing to load due to there being not enough system resources...
storing the cab file as appended data is a better approach for large cab files...

Vortex,

I'm not sure to understand what you mean. As a library function ? If so, I did write one but I find it like overhead to call a callback function from the callback function to make possible custom action like incrementing a progress bar or displaying the file extracted.



evlncrn8,

I got the idea from iexpress.exe (Windows build-in) because it include the cab file as a RT_RCDATA resource. You're probably right that it is not the ultimate solution for huge archive but for something like medium/small program installation for example (less than 100Mb cab file) it is a working solution.


Vortex

Hi Jdoe,

The idea is to convert the .cab file to a MS COFF object module. This can be done with a help of a tool like Hutch's File Data Assembler fda.exe ( \masm32\tools\fda )

fda cabfile.cab cabfile.obj pData

You can link the object file with your project modules to get the final executable.:

.
.
EXTERN pData:BYTE
.
.
mov eax,OFFSET pData ; referencing the binary data block containing the cab file
.
.

jdoe


Hi Vortex,

I gave a try to FDA. It's bullshit... No, I'm kidding   :P

In fact it worked perfectly and it saves few lines of code, the one messing with ressources.

Thanks for pointing me out this tool.

:U


jdoe


I've improved two parts... the create folder function and the callback function which don't need any local variable now.



CreateFolder PROC USES esi p_lpszPath:DWORD

    mov esi, p_lpszPath

@@:
    invoke StrChr, esi, '\'
    test eax, eax
    jz @F

    mov esi, eax
    mov byte ptr [esi], 0

    invoke CreateDirectory, p_lpszPath, NULL

    mov byte ptr [esi], '\'
    add esi, 1

    jmp @B

@@:
    ret

CreateFolder ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CabEx_FileCallback PROC p_Context:DWORD, p_Notification:DWORD, p_Param1:DWORD, p_Param2:DWORD

    .if (p_Notification == SPFILENOTIFY_FILEINCABINET)

        push edi

        mov edi, p_Param1

        invoke lstrcpy, addr [edi].FILE_IN_CABINET_INFO.FullTargetName, p_Context
        invoke lstrcat, addr [edi].FILE_IN_CABINET_INFO.FullTargetName, [edi].FILE_IN_CABINET_INFO.NameInCabinet

        invoke CreateFolder, addr [edi].FILE_IN_CABINET_INFO.FullTargetName

        pop edi

        mov eax, FILEOP_DOIT

    .else

        mov eax, NO_ERROR

    .endif

    ret

CabEx_FileCallback ENDP