Как вызвать 64 битную функцию из 32 битного приложения?

Тема в разделе "WASM.X64", создана пользователем ziral2088, 15 мар 2010.

  1. ziral2088

    ziral2088 New Member

    Публикаций:
    0
    Регистрация:
    16 авг 2009
    Сообщения:
    283
    Нужно вызвать 64 битную функцию из 32 битного приложения. В частности: SetWindowLongPtr
    Если вызвать 32 битную, то данная функция меняет только нижние 32 бита поля в удаленном 64 битном процессе.

    У кого какие идеи? =)
     
  2. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    o Делегировать задачу отдельному 64х-битному процессу.

    o Использовать переходник для прыжка в 64х-разрядный сегмент (far call), подгрузить нужные 64х-разрядные библиотеки и вызвать апи, затем вернуться в 32х-разрядный сегмент (retf). Библиотека ntdll x64 в просессах x32 присутствует, так что native api доступен. Данный подход применялся партнёром нас (актуально, эта сущность делала высказывания о возможности автоматизировать весь процесс вызова х64-апи, но дальше двойной компиляции приплюснутого кода и слинковывания в один экзешник х32 и х64 объектников дело, насколько нам известно, до сих по не зашло). [Привет, Huey].
    Одно предупреждение – в последнем случае нужно соблюдать некоторые правила (волатильность регистров, выравнивание стека, CC, etc).
     
  3. Partner

    Partner Павел

    Публикаций:
    0
    Регистрация:
    28 фев 2008
    Сообщения:
    917
    Адрес:
    Los Angeles
    Или COM object в 64-bit DLL. Инстанциировать как outprocess (surrogate)
     
  4. ziral2088

    ziral2088 New Member

    Публикаций:
    0
    Регистрация:
    16 авг 2009
    Сообщения:
    283
    Делегировать задачу или делать через СОМ ддлку не очень хочется.

    А кусочек кода или псевдокода можно? То есть что бы было с чего начать. К примеру куда прыгать переходником то.
     
  5. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Legacy Mode:
    Код (Text):
    1. #define KGDT_NULL              (0x00)
    2. #define KGDT_R0_CODE           (0x08)
    3. #define KGDT_R0_DATA           (0x10)
    4. #define KGDT_R3_CODE           (0x18)        <- Ты здесь (Legacy Mode).
    5. #define KGDT_R3_DATA           (0x20)
    6. #define KGDT_TSS               (0x28)
    7. #define KGDT_R0_PCR            (0x30)
    8. #define KGDT_R3_TEB            (0x38)
    9. #define KGDT_R3_VDM            (0x40)
    10. #define KGDT_LDT               (0x48)
    11. #define KGDT_DF_TSS            (0x50)
    12. #define KGDT_NMI_TSS           (0x58)
    Long Mode:
    Код (Text):
    1. #define KGDT64_NULL            (0x00)
    2. #define KGDT64_R0_CODE         (0x10)
    3. #define KGDT64_R0_DATA         (0x18)
    4. #define KGDT64_R3_CMCODE       (0x20)        <- Ты здесь (Compatibility Mode).
    5. #define KGDT64_R3_DATA         (0x28)
    6. #define KGDT64_R3_CODE         (0x30)        <- Тебе надо сюда (x64 Mode).
    7. #define KGDT64_SYS_TSS         (0x40)
    8. #define KGDT64_R3_CMTEB        (0x50)
    9. #define KGDT64_R0_CMCODE       (0x60)
    10. #define KGDT64_LAST            (0x70)
    Простейший пример – получение адреса и лимита GDT для текущего процессора из Legacy\Compatibility mode.
    Код (Text):
    1. PUVOID64 FASTCALL GetGdt(DWORD* Limit = NULL);
    2.  
    3. GetGdt:
    4.     xor edx, edx
    5.     mov ax, cs
    6.     push edx
    7.     push edx
    8.     push edx
    9.     sgdt [esp + 2]
    10.     cmp al, $23                    ; KGDT64_R3_CMCODE | RPL_MASK
    11.     jne @f
    12.     call 0x33:GetGdt_x64Mode       ; KGDT64_R3_CODE | RPL_MASK
    13. @@:
    14.     pop edx
    15.     shr edx, 10h
    16.     test ecx, ecx
    17.     jz @f
    18.     mov [ecx], edx
    19. @@:
    20.     pop eax
    21.     pop edx
    22.     retn
    23.  
    24.    
    25. GetGdt_x64Mode:
    26. ;
    27. ; Всё, мы в подрежиме x64.
    28. ; Необходимо заметить, что здесь мы даже не переключили режим генерации ассемблерных команд  – таким образом,
    29. ; на самом деле выполняются инструкции "sgdt [rsp + 8 + 2]; retfd;". Если бы кусок кода был больше, можно было
    30. ; бы переключить режим ассемблирования в этом месте – для фасма используется директива "use64".
    31. ; Также необходимо обратить внимание на то, что для выхода используется "retfd" – дальний ret с 32х-разрядным
    32. ; размером операнда. Это для того, чтобы соответствовать разрядности операнда начального call far.
    33. ;
    34.     sgdt [esp + 8 + 2]            ; call pushed 2 dwords on stack
    35.     retfd
    Также прикладываем микротулзу для базового конверта х64-объектников в 32х-разрядные, для дальнейшей прилинковки стандартным компоновщиком от MS.

    P.S.
    Надеемся вскоре увидеть качественный кросплатформенный продукт. Лол.
     
  6. ziral2088

    ziral2088 New Member

    Публикаций:
    0
    Регистрация:
    16 авг 2009
    Сообщения:
    283
    Загрузив дллки в процесс, получил:
    400000 4bb1bd1c Mar 30 11:58:04 2010 Z:\Share\main.exe
    77ec0000 49901574 Feb 09 13:37:24 2009 C:\WINDOWS\system32\ntdll.dll
    78be0000 42438b79 Mar 25 05:54:33 2005 C:\WINDOWS\system32\wow64.dll
    78b90000 42438b79 Mar 25 05:54:33 2005 C:\WINDOWS\system32\wow64win.dll
    78b80000 42438b7a Mar 25 05:54:34 2005 C:\WINDOWS\system32\wow64cpu.dll
    3870000 49c52144 Mar 21 19:17:56 2009 C:\WINDOWS\System32\kernel32.dll
    39f0000 45e7bfcb Mar 02 08:10:19 2007 C:\WINDOWS\System32\user32.dll
    3b00000 49006dd0 Oct 23 15:28:00 2008 C:\WINDOWS\system32\GDI32.dll

    Вопрос: как сделать что бы 64 битные либы загрузились по оригинальным адресам? По тем что они загрузились они фурычить не хотят. (Грузил либы через LdrLoadDll)
     
  7. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Да, сейчас проверили – верхние адреса действительно зарезервированы:
    Код (Text):
    1. lkd> !process 0 1 notepad.exe
    2. PROCESS fffffa8002015b30
    3.     SessionId: 3  Cid: 0f50    Peb: 7efdf000  ParentCid: 0eb4
    4.     DirBase: 53fe1000  ObjectTable: fffff8a0107f3c30  HandleCount:   0.
    5.     Image: notepad.exe
    6.     VadRoot fffffa80044de5b0 Vads 18 Clone 0 Private 23. Modified 0. Locked 0.
    7.     DeviceMap 0000000000000000
    8.     Token                             fffff8a0041f8510
    9.     ElapsedTime                       00:01:00.397
    10.     UserTime                          00:00:00.000
    11.     KernelTime                        00:00:00.000
    12.     QuotaPoolUsage[PagedPool]         0
    13.     QuotaPoolUsage[NonPagedPool]      0
    14.     Working Set Sizes (now,min,max)  (43, 50, 345) (172KB, 200KB, 1380KB)
    15.     PeakWorkingSetSize                43
    16.     VirtualSize                       4 Mb
    17.     PeakVirtualSize                   4 Mb
    18.     PageFaultCount                    38
    19.     MemoryPriority                    BACKGROUND
    20.     BasePriority                      8
    21.     CommitCharge                      108
    22.     DebugPort                         fffffa80044ad060
    23.  
    24. lkd> !vad fffffa80044de5b0
    25. VAD             level      start      end    commit
    26. fffffa800499dc70 ( 4)         10       2f        32 Private      READWRITE        
    27. fffffa8003d75980 ( 3)         30       31         2 Private      READWRITE        
    28. fffffa8003bfc010 ( 2)         40       40         0 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\apisetschema.dll
    29. fffffa800478c950 ( 4)         50       53         0 Mapped       READONLY           Pagefile-backed section
    30. fffffa8002ac90e0 ( 3)         60       61         0 Mapped       READONLY           Pagefile-backed section
    31. fffffa8002519590 ( 4)         70       70         1 Private      READWRITE        
    32. fffffa8001b9dda0 ( 1)         a0       df         7 Private      READWRITE        
    33. fffffa800454b2e0 ( 3)        2a0      2df        19 Private      READWRITE        
    34. fffffa8004717f80 ( 2)        300      32f         3 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\SysWOW64\notepad.exe
    35. fffffa80044f9390 ( 3)      77bc0    77d6a        13 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\ntdll.dll
    36. fffffa8002feea40 ( 4)      77da0    77f1f         9 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\SysWOW64\ntdll.dll
    37. fffffa80044de5b0 ( 0)      7efb0    7efd2         0 Mapped       READONLY           Pagefile-backed section
    38. fffffa800204b930 ( 3)      7efdb    7efdd         3 Private      READWRITE        
    39. fffffa8004325b90 ( 2)      7efde    7efde         1 Private      READWRITE        
    40. fffffa80044c9c30 ( 3)      7efdf    7efdf         1 Private      READWRITE        
    41. fffffa8004446e00 ( 1)      7efe0    7ffdf         0 Private      READONLY          
    42. fffffa8001d96010 ( 2)      7ffe0    7ffef        -1 Private      READONLY          
    43. fffffa8002a3e380 ( 3)      7fff0 7fffffef        -1 Private      READONLY          
    44.  
    45. Total VADs:    18  average level:    3  maximum depth: 4
    46. lkd> !vad fffffa8002a3e380 1
    47.  
    48. VAD @ fffffa8002a3e380
    49.   Start VPN                7fff0  End VPN         7fffffef  Control Area  0000000000000000
    50.   FirstProtoPte 0000000000000000  LastPte 0000000000000000  Commit Charge         ffffffff (-1.)
    51.   Secured.Flink         7fff0001  Blink        7fffffeffff  Banked/Extend                0
    52.   File Offset                  0  
    53.       ViewUnmap NoChange PrivateMemory READONLY          
    54.       OneSecured
    Посмотри на последний VAD. Он описывает регион адресного пространства 7fff_0000...7ff`fffe_ffff. Кроме того, обрати внимание на флаги: 'NoChange' говорит о том, что нельзя менять атрибуты защиты страниц, а 'OneSecured' – о том, что участок Secured.Flink...Blink застрахован. Короче говоря, освободить этот огромный регион не получится.
    Хотя можно расширить доступное для 32х-битного приложения АП до 4х гигабайт, установив соответствующий флаг в хидере главного модуля процесса (/LargeAddressAware).

    Судя по немедленному отсутствию ненативной ntdll и базе kernel32 это у тебя nt5? Что за версия? Странно, что kernel32 промапилась по такому адресу – по идее даже у 64х-битных версий её дефолтная база ниже 2GB.

    ziral2088
    >как сделать что бы 64 битные либы загрузились по оригинальным адресам? По тем что они загрузились они фурычить не хотят.
    Вывод о неработоспособности из-за релокации выглядит преждевременным. Копай глубже ;)
     
  8. ziral2088

    ziral2088 New Member

    Публикаций:
    0
    Регистрация:
    16 авг 2009
    Сообщения:
    283
    До этого грузил ддлки так:
    LdrLoadDll kenrel32
    LdrLoadDll user32

    Попробовал сразу загрузить user32, в итоге получил ошибку.
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    ziral2088
    Загрузчик перед выполнением релокации модулей в LdrpMapDll() проверяет имя, если это Kernel32 или User32(пер. Kernel32String и User32String соответственно), то генерирует исключение STATUS_ILLEGAL_DLL_RELOCATION - для этих двух модулей не может применяться релокация, так как в них ссылки глобальные в системе(для всех процессов). Вам нужно изменить имена модулей.
     
  10. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Clerk
    >user32
    Это наверное только на nt5. В w7 (да и в висте, IWRC) user32.dll может релоцироваться. На самом деле неясно, почему до сих пор присутствует проверка базы kernel32.dll – возможно, для совместимости с пользовательским кодом, полагающимся на неперемещаемость этой длл. [Упреждая "стартовый адрес потока" (который _ethread.StartAddress): сейчас вместо kernel32!BaseProcessStartThunk \ kernel32!BaseThreadStartThunk используется единообразный ntdll!RtlUserThreadStart].

    ziral2088
    Тотально окей запросить базовую информацию для старта. Но направлять каждый шаг не будет никто – особенно когда направляемый игнорирует вопросы. И ты правда хочешь завершить иллегальное кроссбитное нечто и при этом не можешь воспользоваться ни отладчиком, ни mspaint'ом? Серьёзно, на этом этапе нам начинает казаться, что тебе лучше бросить это – гоккокода в Сети и так хватает.