Search code examples
cwinapicode-injectiondll-injection

Injected dll crashes the owner process. Why?


I have a dll that I injected in a process. It searches 'file://' until it finds invalid symbol. After a few mins it crashes the main process. Why is that? How can I check? I found that with smaller stack size on CreateThread it crashes faster, so it can be somehow stack overflow, but I'm not allocating nothing, but a single struct.

BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:

        CreateThread(NULL, 500, SampleFunction, 0, 0, NULL);            
            break;

        case DLL_THREAD_ATTACH:

            break;

        case DLL_THREAD_DETACH:
            break;

        case DLL_PROCESS_DETACH:
            break;
    }

    /* Return success */
    return TRUE;
}



int Send(char* strDataToSend) {
    HWND hWnd = FindWindow(NULL, "Test");
    if (hWnd) {
        COPYDATASTRUCT cpd;
        cpd.dwData = 0;
        cpd.cbData = (strlen(strDataToSend) + 1) * 2;
        cpd.lpData = (PVOID)strDataToSend;
        SendMessage(hWnd, WM_COPYDATA, (WPARAM) hWnd, (LPARAM)&cpd);
    }
}

int isurl(char c) {
    char* chars = "-._~:/?#[]@!$&'()*+,;=%";
    for(int i = 0; i < strlen(chars); i++) {
        if (chars[i] == c || isalnum(c)) {
            return 1;
        }           
    }

    return 0;
}

TESTDLLMAPI void WINAPI SampleFunction(void) {
    MessageBox(0,"LOADED !",0,0);
    MEMORY_BASIC_INFORMATION info;  
    MEMORY_BASIC_INFORMATION* pinfo = &info;

    while(1) {


    int cnt = 0;
    unsigned long addr = 0;
    do {
        ZeroMemory(&info, sizeof(info));

        if (!VirtualQueryEx(GetCurrentProcess(), (LPCVOID) addr, pinfo, sizeof(info))) {
            //MessageBox(0,"FAILED",0,0);
        }       

            if (info.State == 0x1000) {
            if (info.Protect == PAGE_READONLY || info.Protect == PAGE_READWRITE) {
                __try {

                if (info.RegionSize < 128) continue;

                for(long i = 0; i < info.RegionSize - 10; i+=7) {

                char* buff = info.BaseAddress;
                    if (buff[i] == 'f' && buff[i+1] == 'i' && buff[i+2] == 'l' && buff[i+3] == 'e' && buff[i+4] == ':' && buff[i+5] == '/' && buff[i+6] == '/') {

                        long start = i;
                        long end   = start+7;

                        while(end < info.RegionSize - 10 && isurl(buff[end])) end++; 

                        int len = end - start + 1;
                        char* test = (char*) calloc(len, 1);
                        //memcpy(test, buff+start, len);
                        int k = 0;
                        for (int j = start; j <= end; j++, k++) {
                            test[k] = buff[j];
                        }


                            Send(test);
                                                    free(test); 
                            cnt++;      
                        }

                    }
                } __finally {}
            }
        }

        addr = (unsigned long) info.BaseAddress + (unsigned long) info.RegionSize;
    } while (addr != 0 && addr < 0x7FFF0000);

    Sleep(1000);

}

Solution

  • In your Send function you're setting the buffer size to the length of the string x2 but you are passing the data in a pointer to a char, which is one byte.


    A few more tips:

    • You're reading memory in increments of 7 at a time. There are two problems with this:
      • as an example, what if the end of info.RegionSize - 10 is at 500000, and i = 499999? You'll read 6 bytes past which will cause a crash.
      • "file://" isn't necessarily going to be found at a place in memory with an address that is a multiple of 7. If you happen to be testing "123file://...." then you'll simply miss it, because you'll find "123file" and "://...."
    • VirtualQueryEx(GetCurrentProcess(), ... is redundant. Just use VirtualQuery.
    • You're calling VirtualQuery with the address 0.
    • There is a much easier way to perform the string-comparison you are trying to accomplish - strstr.
    • Is it just me or is that do/while an infinite loop?
    • Your function isn't even closed.
    • I can't see what purpose cnt is supposed to serve.
    • You created a thread in DllMain. you should close handles to threads with CloseHandle once you're no longer going to use them (in this case, i.e. right after you've created it)

    I rewrote your SampleFunction for you. I wrote the on the go and it probably won't compile, but you should get the general idea.

    #include <windows.h>
    
    BOOL IsPageReaable(PMEMORY_BASIC_INFORMATION pmbi)
    {
      if (pmbi->Protect & PAGE_GUARD)
        return FALSE;
    
      if (pmbi->Protect &
        (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE
        | PAGE_EXECUTE_WRITECOPY | PAGE_READONLY
        | PAGE_READWRITE | PAGE_WRITECOPY))
        return TRUE;
    
      return FALSE;
    }
    
    #define POLL_INTERVAL 1000
    
    TESTDLLMAPI VOID WINAPI SampleFunction(VOID)
    {
      MEMORY_BASIC_INFO mbi;
      ULONG_PTR         ulAddress = GetModuleHandle(NULL); // base address
      LPSTR             lpszBase;
    
      ZeroMemory(&mbi, sizeof(mbi));
      if (!VirtualQuery(ulAddress, &mbi, sizeof(mbi)))
        return;
    
      if (!IsPageReadable(&mbi))
        return;
    
      lpszBase = info.BaseAddress;
      for (;; Sleep(POLL_INTERVAL))
      {
        for (ULONG_PTR i = 0; i < info.RegionSize; i++)
        {
          int   j;
          LPSTR lpszBuffer;
    
          if (strstr(&lpszBase[i], "file://") == NULL)
            continue;
    
          j = i + 1;
          do {
            j++;
          } while (j < info.RegionSize && isurl(lpszBase[j])
    
          lpszBuffer = (LPSTR)HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, sizeof(CHAR) * (j - i + 1));
          if (lpszBuffer != NULL)
          {
            CopyMemory(lpszBuffer, &lpszBase[i], j - i);
            Send(lpszBuffer);
            HeapFree(GetProcessHeap(), 0, lpszbuffer);
          }
        }
      }
    }