NtWow64ReadVirtualMemory64 & STATUS_PARTIAL_COPY

Тема в разделе "WASM.X64", создана пользователем super_huevo, 29 май 2011.

  1. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
    Доброе время!

    Задача: определить ImageBase 64-битного процесса из 32-битного.

    Для решения я попытался использовать NtWow64ReadVirtualMemory64, но получил ошибку STATUS_PARTIAL_COPY.

    Исходя из дизасма 32-битной ntdll.dll (из папки Wow64), можно понять что два параметра являются 64-битными:

    Код (Text):
    1. .text:7DE8FE80                 public ZwReadVirtualMemory
    2. .text:7DE8FE80 ZwReadVirtualMemory proc near           ; CODE XREF: sub_7DEE31F9+28p
    3. .text:7DE8FE80                                         ; sub_7DF2F608+2C8p
    4. .text:7DE8FE80
    5. .text:7DE8FE80 arg_0           = byte ptr  4
    6. .text:7DE8FE80
    7. .text:7DE8FE80                 mov     eax, 3Ch        ; NtReadVirtualMemory
    8. .text:7DE8FE85                 xor     ecx, ecx
    9. .text:7DE8FE87                 lea     edx, [esp+arg_0]
    10. .text:7DE8FE8B                 call    large dword ptr fs:0C0h
    11. .text:7DE8FE92                 add     esp, 4
    12. .text:7DE8FE95                 retn    14h
    13.  
    14. .text:7DE920F4                 public ZwWow64ReadVirtualMemory64
    15. .text:7DE920F4 ZwWow64ReadVirtualMemory64 proc near
    16. .text:7DE920F4
    17. .text:7DE920F4 arg_0           = byte ptr  4
    18. .text:7DE920F4
    19. .text:7DE920F4                 mov     eax, 1A0h       ; NtWow64ReadVirtualMemory64
    20. .text:7DE920F9                 xor     ecx, ecx
    21. .text:7DE920FB                 lea     edx, [esp+arg_0]
    22. .text:7DE920FF                 call    large dword ptr fs:0C0h
    23. .text:7DE92106                 add     esp, 4
    24. .text:7DE92109                 retn    1Ch
    25. .text:7DE92109 ZwWow64ReadVirtualMemory64 endp ; sp-analysis failed
    Прототип я определил так:

    Код (Text):
    1. typedef NTSTATUS (NTAPI *NTWOW64READVIRTUALMEMORY)(
    2.     IN HANDLE ProcessHandle,
    3.     IN ULONG64 BaseAddress,
    4.     OUT ULONG64 Buffer,
    5.     IN SIZE_T BufferLength,
    6.     OUT PULONG ReturnLength OPTIONAL
    7. );
    Исходя из того, что параметры BaseAddress & Buffer являются 64-битными. Методом исключения, т.к. ProcessHandle процесса в 32-битном коде явно 4 байта, а BufferLength и ReturnLength не имеет смысла делать 64-битными, так как 32-битное приложение не может иметь размер виртуальной памяти свыше 4ГБ.

    Итак, я написал примерно такой код:

    Код (Text):
    1. ULONG64 GetProcessBase (IN HANDLE hProcess, IN BOOL x64)
    2. {
    3. //#ifndef WIN64
    4.     PROCESS_BASIC_INFORMATION pbi;
    5.     PEB peb;
    6. //#else
    7.     //PROCESS_BASIC_INFORMATION64 pbi64;
    8.     PEB64 peb64;
    9. //#endif
    10.     NTSTATUS st;
    11.  
    12.     if (x64)
    13.     {
    14.         st = NtQueryInformationProcess (hProcess, ProcessBasicInformation, &pbi, sizeof (pbi), NULL);
    15.  
    16.         if (NT_SUCCESS(st))
    17.         {
    18.             DebugWrite("pbi.PebBaseAddress == 0x%p", pbi.PebBaseAddress);
    19. #ifndef WIN64
    20.             NTWOW64READVIRTUALMEMORY lpNtWow64ReadVirtualMemory64 = (NTWOW64READVIRTUALMEMORY)_GetProcAddressThroughHash(GetNtdllBase(), 0x50968A4A);
    21.             ULONG64 PebAddress = (ULONG64)pbi.PebBaseAddress;
    22.             ULONG64 BufferAddress = (ULONG64)&peb64;
    23.             ULONG RerurnLength;
    24.             st = lpNtWow64ReadVirtualMemory64 (hProcess, PebAddress, BufferAddress, sizeof (peb64), &RerurnLength);
    25. #else
    26.             st = NtReadVirtualMemory (hProcess, pbi.PebBaseAddress, &peb64, sizeof (peb64), NULL);
    27. #endif
    28.  
    29.             if (NT_SUCCESS(st))
    30.             {
    31.                 _WriteFile("C:\\pebdump.bin", (PBYTE)&peb64, sizeof(peb64), 0);
    32.  
    33.                 return peb64.ImageBaseAddress;
    34.             }
    35.         }
    36.     }
    37.     else
    38.     {
    39.         st = NtQueryInformationProcess (hProcess, ProcessBasicInformation, &pbi, sizeof (pbi), NULL);
    40.  
    41.         if (NT_SUCCESS(st))
    42.         {
    43.             DebugWrite("[ERROR] : pbi.PebBaseAddress == 0x%p", pbi.PebBaseAddress);
    44.             st = NtReadVirtualMemory (hProcess, pbi.PebBaseAddress, &peb, sizeof (peb), NULL);
    45.  
    46.             if (NT_SUCCESS(st))
    47.             {
    48.                 _WriteFile("C:\\pebdump.bin", (PBYTE)&peb, sizeof(peb), 0);
    49.                
    50.                 return (ULONG64)peb.ImageBaseAddress;
    51.             }
    52.         }
    53.     }
    54.  
    55.     return NULL;
    56. }
    Но чёто lpNtWow64ReadVirtualMemory64 возвращает STATUS_PARTIAL_COPY, а RerurnLength == 0.

    PEB64 описывал так:

    http://www.everfall.com/paste/id.php?bh8ptyyc3sow

    Не могу понять что-то почему не работает данный код. Как приблизиться к решению в данном случае? Нужно брать ядерный отладчик и смотреть что не так с сервисом NtWow64ReadVirtualMemory64 ?
     
  2. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
    Хотя если PEB (именно PEB, а не PEB64) читать просто через NtReadVirtualMemory по тому же адресу, то ImageBase будет равен 0x40000000. Притом что оригинальный ImageBase вроде как равен 0x0000000140000000, это видно из PE-заголовка.

    [​IMG]

    Ничего похожего на адрес ImageBase в дампе нет:

    [​IMG]

    Почему?
     
  3. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
    Хотя вот сейчас попытался прочитать что-нибудь из точки входа:

    Код (Text):
    1.             NTWOW64READVIRTUALMEMORY lpNtWow64ReadVirtualMemory64 = (NTWOW64READVIRTUALMEMORY)_GetProcAddressThroughHash(GetNtdllBase(), 0x50968A4A);
    2.             ULONG64 SrcAddress = (ULONG64)0x0000000140000000;
    3.             BYTE smth[0x1000];
    4.             ULONG64 BufferAddress = (ULONG64)smth;
    5.             ULONG RerurnLength;
    6.             st = lpNtWow64ReadVirtualMemory64 (hProcess, SrcAddress, BufferAddress, sizeof (smth), &RerurnLength);
    И нифига. STATUS_ACCESS_VIOLATION

    Вообще, надо добавить что все эти операции я совершаю до вызова NtResumeThread.

    И что тогда всё это значит? Процесс ещё не "проинициализирован"? Загрузчик Windows не промапил секции PE-файла в память? Как быть?
     
  4. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
    А. Ну вроде понятно.

    http://drdobbs.com/high-performance-computing/184401966
    То есть надо использовать ntdll!NtWow64QueryInformationProcess64() просто. В этом случае адрес PEB'а получается 0x000007fffffda000.

    Однако что-то не могу заставить NtWow64ReadVirtualMemory64 читать по этому адресу.
     
  5. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
    Хз. NtWow64ReadVirtualMemory64 возвращает STATUS_INFO_LENGTH_MISMATCH ( если destination-буфер сделать бОльшим, то будет возвращать STATUS_ACCESS_VIOLATION ).
    Причём процесс инициализирован, память по адресу, откуда я пытаюсь читать выделена и права соответствуют:

    [​IMG]
     
  6. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
  7. super_huevo

    super_huevo New Member

    Публикаций:
    0
    Регистрация:
    29 май 2011
    Сообщения:
    17
    Всё. Разобрался.

    Оказывается прототип должен быть такой:

    Код (Text):
    1. typedef NTSTATUS (NTAPI *NTWOW64READVIRTUALMEMORY)(
    2.     IN HANDLE ProcessHandle,
    3.     IN ULONG64 BaseAddress,
    4.     OUT PVOID Buffer,
    5.     IN ULONG64 BufferLength,
    6.     OUT PULONG ReturnLength OPTIONAL
    7. );
     
  8. blast

    blast New Member

    Публикаций:
    0
    Регистрация:
    8 мар 2008
    Сообщения:
    170
    по поводу прототипа если параметр ULONG64 BufferLength - 64 то логично предположить что PULONG ReturnLength должно быть тоже 64 - PULONG_PTR ReturnLength

    Еще насколько я знаю в windows xp 64 нету NtWow64 функций.