News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

How to fix a deadlock in LoadLibrary Api ?

Started by guga, April 13, 2020, 05:33:37 AM

Previous topic - Next topic

guga

#15
Hi Guys

I found the problem. Indeed there is a very rare and uncommon error inside LoadLibraryExW when it reaches LdrLoadDll in ntdll.dll. In windows10 (for 64 bits), for some odd reason, in rare situations the stack is changed in one of the functions used internally the loadlibrary api.
Image1


I´m making some tests on a rebuild of t6his LoadLibraryExW to see if it can fix the error. So far, my rebuild is like this (untested yet)


Proc LoadLibraryExW::
    Arguments @lpLibFileName, @hFile, @dwFlags
    Local @DllCharacteristics, @BaseAddress, @Var1, @Var2, @AndFlag, @NTStatus, @SearchPathFlag
    Structure @UnicodeString 8, @UnicodeString.LenghtDis 0, @UnicodeString.MaximumLenghtDis 2, @UnicodeString.BufferDis 4
    Uses ebx, esi, ecx, edx

    ; LOAD_LIBRARY_AS_DATAFILE and  LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE cannot be combined
    mov eax D@dwFlags | and eax &LOAD_LIBRARY_AS_DATAFILE__&LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | mov D@AndFlag eax
    If_Or D@lpLibFileName = 0, D@hFile <> 0, D@dwFlags > 0FFFF, eax = &LOAD_LIBRARY_AS_DATAFILE__&LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
        call BaseSetLastNTError &STATUS_INVALID_PARAMETER
        xor eax eax
        ExitP
    End_If

    call RtlInitUnicodeStringEx D@UnicodeString, D@lpLibFileName
    If eax <> &STATUS_SUCCESS
        call BaseSetLastNTError eax
        xor eax eax
        ExitP
    Else_If W@UnicodeString.LenghtDis = 0
        call BaseSetLastNTError &STATUS_INVALID_PARAMETER
        xor eax eax
        ExitP
    End_If


    ; Verify if the string ends with spaces. If it do recalculate the lenght without them.
    movzx ecx W@UnicodeString.LenghtDis | sub ecx 2 ; don´ count the null terminated byte
    mov edx D@UnicodeString.BufferDis
    While W$edx+ecx = ' '
        sub ecx 2
    End_While
    add ecx 2 ; add the next word to we have the full lenght
    If cx = 0
        call BaseSetLastNTError &STATUS_INVALID_PARAMETER
        xor eax eax
        ExitP
    End_If
    mov W@UnicodeString.LenghtDis cx

    mov eax D@dwFlags
    mov ebx eax
    mov D@BaseAddress 0
    and eax 07F08 ; &LOAD_WITH_ALTERED_SEARCH_PATH convert to DllCharacteristics . Weird, weird value, since the DwFlags, have at most the bit 12 activated.
                            ; Therefore, this should be and eax 01F08 ? Also, maybe necessary build some flag coherence checks to because LOAD_LIBRARY_SEARCH_DEFAULT_DIRS is not the combination of the equates said in the official documentation.
                            ; Also, there seems to be some sort of ilogical situation. If the flags are checked to jmp over when it don´t have &LOAD_LIBRARY_AS_DATAFILE__&LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE__&LOAD_LIBRARY_AS_IMAGE_RESOURCE
                            ; Therefore, a check is necessary to avoid the user to input those flags combined with &DONT_RESOLVE_DLL_REFERENCES, &LOAD_IGNORE_CODE_AUTHZ_LEVEL, &LOAD_WITH_ALTERED_SEARCH_PATH
                            ; But, before implementing this check, i need to analyze what´s going on with LdrGetDllPath and BasepLoadLibraryAsDataFile

    ;mov eax (Not &IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE__&LOAD_WITH_ALTERED_SEARCH_PATH)
    ; https://www.cyberforum.ru/blogs/172954/blog5934.html
    ; mov eax (not &LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY__&LOAD_WITH_ALTERED_SEARCH_PATH)
    mov D@SearchPathFlag eax

    ; only files with bl flag as &LOAD_LIBRARY_AS_DATAFILE__&LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE__&LOAD_LIBRARY_AS_IMAGE_RESOURCE are allowed here.
    ; So, the flags: &DONT_RESOLVE_DLL_REFERENCES, &LOAD_IGNORE_CODE_AUTHZ_LEVEL, &LOAD_WITH_ALTERED_SEARCH_PATH cannot be combined with those above
    ...Test_If bl &LOAD_LIBRARY_AS_DATAFILE__&LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE__&LOAD_LIBRARY_AS_IMAGE_RESOURCE;062
        lea edx D@Var2
        lea ecx D@Var1
        ; from wine: https://git.froggi.es/tkg/PKGBUILDS/commit/6be3bb886b5748b63669475aadb314cf8abcbf3e
        ; https://github.com/wine-mirror/wine/blob/master/dlls/ntdll/loader.c
        call 'ntdll.LdrGetDllPath' D@UnicodeString.BufferDis, D@SearchPathFlag, ecx, edx
        If eax <> &STATUS_SUCCESS
            call BaseSetLastNTError eax
            xor eax eax
            ExitP
        End_If
        lea eax D@BaseAddress
        call BasepLoadLibraryAsDataFile D@UnicodeString, D@Var2, D@dwFlags, eax, D@Var1
        mov D@NTStatus eax

        .If eax >s= &STATUS_SUCCESS
            call 'ntdll.RtlReleasePath' D@Var1
            mov eax D@BaseAddress
            ExitP
        .Else_If eax = &STATUS_NO_SUCH_FILE
            call 'ntdll.RtlReleasePath' D@Var1
            call BaseSetLastNTError D@NTStatus ; status Parameter at ecx
            xor eax eax
            ExitP
        .Else
            .Test_If bl &LOAD_LIBRARY_AS_IMAGE_RESOURCE
                If D@AndFlag <> 0
                    lea eax D@BaseAddress
                    call BasepLoadLibraryAsDataFile D@UnicodeString, D@Var2, D@AndFlag, eax, D@Var1
                    mov D@NTStatus eax
                End_If
            .Test_End
            call 'ntdll.RtlReleasePath' D@Var1
        .End_If

    ...Test_Else

        or D@SearchPathFlag 1
        call LoadFlagsToDllCharacteristics D@dwFlags
        mov D@DllCharacteristics eax

        lea edx D@BaseAddress
        lea ecx D@DllCharacteristics
        call 'ntdll.LdrLoadDll' D@SearchPathFlag, ecx, D@UnicodeString, edx
        mov D@NTStatus eax

    ...Test_End

    If D@NTStatus >s= &STATUS_SUCCESS
        mov eax D@BaseAddress
    Else
        call BaseSetLastNTError D@NTStatus; status Parameter at ecx
        xor eax eax
    End_If

EndP




Proc LoadFlagsToDllCharacteristics:
    Arguments @LoadFlags
    Uses ecx

    mov ecx D@LoadFlags

    xor eax eax
    Test_If cl &DONT_RESOLVE_DLL_REFERENCES
        mov eax &IMAGE_FILE_EXECUTABLE_IMAGE
    Test_End

    ;If cl <s 0; same as Test_If cl 080 &LOAD_LIBRARY_REQUIRE_SIGNED_TARGET
     ;   or eax 0800000
    ;End_If

    Test_If cl &LOAD_LIBRARY_REQUIRE_SIGNED_TARGET; from: https://www.cyberforum.ru/blogs/172954/blog5934.html
        or eax 0800000
    Test_End

    Test_If cl &LOAD_PACKAGED_LIBRARY; from: https://www.cyberforum.ru/blogs/172954/blog5934.html
        or eax 4
    Test_End

    Test_If ecx &LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY; from: https://www.cyberforum.ru/blogs/172954/blog5934.html
        or eax 080000000
    Test_End

EndP




Proc BaseSetLastNTError:
    Arguments @Status
    Uses esi, ecx, edx

    call 'ntdll.RtlNtStatusToDosError' D@Status
    mov esi eax
    call 'ntdll.RtlSetLastWin32Error' eax
    mov eax esi

EndP


before i finish rebuilding this, i´ll make a couple of tests on LdrLoadDll on a smaller version of the loadlibrary rebuild, just to make sure if it is the one that is ruining the stack before i try to rebuild this thing completely. Maybe using a smaller variation only with this ntdll api, would be enough .
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Quote from: guga on April 16, 2020, 07:09:38 AMIn windows10 (for 64 bits), for some odd reason, in rare situations the stack is changed

Probably unrelated to http://masm32.com/board/index.php?topic=8458.msg92581#msg92581 but it may indicate that M$ is fumbling with the design of Win10

guga

Quote from: jj2007 on April 16, 2020, 12:39:34 PM
Quote from: guga on April 16, 2020, 07:09:38 AMIn windows10 (for 64 bits), for some odd reason, in rare situations the stack is changed

Probably unrelated to http://masm32.com/board/index.php?topic=8458.msg92581#msg92581 but it may indicate that M$ is fumbling with the design of Win10

Indeed, definitely is some weird stack problem that windows10 is not being able to handle. Although i never store huge data in the stack using local variables, windows is doing a mess-up with the stack somehow.

I´m finishing rebuilding another internal function called BasepTrackDataFileHandle. The main problem i see in windows kernelbase.dll is that it heavily contains spaghetti coding style and also function chunks all over the place rather inside their own procedures. I really thought M$ have fixed this weird style of compilation, but, it seems they didn´t. It have the same horror as i saw in some windowsXp core functions. To get things worst, there is unused code and flags insides this LoadLibrayExW that seems to be a left over or simply  junk code to be used later.

I´ll see during this night  if i can make it work with a tiny variation of LoadLibrary without the inner code that uses the flags LOAD_LIBRARY_AS_DATAFILE, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE and LOAD_LIBRARY_AS_IMAGE_RESOURCE. Since inside RosAsm, the functions that uses LoadLibrary don´t actually uses those flags, then, perhaps if i made a small routine to directly use LdrLoadDll to get the handles of the dlls, it may works.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

hutch--

Guga, can you get your hands on an old SDK tool called Depends.exe. That will give you something like a dependency tree as this sounds like what your problem is.

guga

Quote from: hutch-- on April 16, 2020, 02:56:06 PM
Guga, can you get your hands on an old SDK tool called Depends.exe. That will give you something like a dependency tree as this sounds like what your problem is.

Hi Steve. Is dependencywalker, right ? Good idea :thumbsup: :thumbsup:. I´ll download it and see what it shows to me.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

aw27

I can only guess the mess that RosAsm itself is so that mr. guga is not able to isolate the piece of code responsible for the imaginary problem, build a model and show to everybody. This is called a proof of concept.
Instead, blames Microsoft and ffmpeg the King Trump way without presenting any evidence. This sucks.

TimoVJL

May the source be with you

guga

Quote from: AW on April 16, 2020, 03:24:35 PM
I can only guess the mess that RosAsm itself is so that mr. guga is not able to isolate the piece of code responsible for the imaginary problem, build a model and show to everybody. This is called a proof of concept.
Instead, blames Microsoft and ffmpeg the King Trump way without presenting any evidence. This sucks.

Don´t forget your pills :badgrin: :badgrin: :badgrin:
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

aw27

Quote from: guga on April 16, 2020, 03:38:00 PM
Quote from: AW on April 16, 2020, 03:24:35 PM
I can only guess the mess that RosAsm itself is so that mr. guga is not able to isolate the piece of code responsible for the imaginary problem, build a model and show to everybody. This is called a proof of concept.
Instead, blames Microsoft and ffmpeg the King Trump way without presenting any evidence. This sucks.

Don´t forget your pills :badgrin: :badgrin: :badgrin:

Try to learn some MASM and Windows API before spamming the forum with beginner problems.

guga

Quote from: TimoVJL on April 16, 2020, 03:35:13 PM
Where that avformat-58.dll came from ?

Hi timo. From here:

https://ffmpeg.zeranoe.com/builds

The version i´m testing is: ffmpeg-20200403-52523b6-win32-shared

To reproduce the error it would be necessary for me do upload the version of RosAsm i´m currently working and also this small piece of code to test. Creating a small app just to assemble one single line using ffmpeg dlls is ok, but the problem happens when i´m testing a bigger app that contains more dlls.

Dependency walker showed me the dll that is used in avformat-58 from where loadlibrary is stucked inside. When it should return to the caller at rosasm.exe, instead it returns to crypt32.dll. I´m not sure yet, why it works for smaller files and not works for bigger ones containing more dlls to analyse.

But, the main problems is not in ffmpeg itself, because it do works. The problem seems how windows10 handles the stack when the dllmain os such dlls contains complex code as in ffmpeg library. I know ffmpeg should keep dllmain more simple, but it doesn´t and yet, still works. Therefore, windows 10 should be able to handle such situations.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

TimoVJL

This doesn't hang.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void __cdecl mainCRTStartup(void)
{
HMODULE hMod = LoadLibrary(TEXT("avformat-58.dll"));
if (hMod) {
FreeLibrary(hMod);
}
ExitProcess(0);
}
00000000  55                       push ebp
00000001  89E5                     mov ebp, esp
00000003  6800000000               push @279
00000008  FF1500000000             call [__imp__LoadLibraryA@4]
0000000E  85C0                     test eax, eax
00000010  7407                     jz 00000019h
00000012  50                       push eax
00000013  FF1500000000             call [__imp__FreeLibrary@4]
00000019  6A00                     push 00
0000001B  FF1500000000             call [__imp__ExitProcess@4]
00000021  5D                       pop ebp
00000022  C3                       ret
May the source be with you

jj2007


hutch--

Hi Guga,

I would be inclined to use LoadLibrary()/GetProcAddress() to get each DLL function address you wish to call first before you call any DLL function. The two API functions work OK in all instances and I have used them for years from Win3.0 to Win10 64 bit with no problems. I of course don't know what your code layout happens to be but I would be very careful about mixing the address code with the function calls. This sounds like what the problem may happen to be.

aw27

Quote from: jj2007 on April 16, 2020, 06:17:52 PM
Quote from: guga on April 16, 2020, 03:38:00 PMDon´t forget your pills :badgrin: :badgrin: :badgrin:

Again, Guga: you are a gentleman! Far too soft :badgrin:

You both could use the isolation period to learn some Masm and Windows API.  :icon_idea:
It is not nice to use the Campus to promote tools without users, it will just scare and confuse newbies that land here for the first time - 99% of them never return.

hutch--

Guys, a favour, I know all of you guys and you are all more or less reasonable human beings, can we keep the invective down as it starts to piss people off and we don't need that here. I have known Guga for many years and he took over the reins from "Betov" with RosAsm and has persevered with what must be a difficult task. Playing in binary has always been a ton of fun.