Что представляет собой поле «Аргументы» на вкладке «Функции» IDA?

Я хочу эффективно находить определенные функции в IDA Pro, используя значение «Аргументы» на вкладке «Функции». Однако для следующих примеров кода, полученных в результате декомпиляции IDA:

__int64 __fastcall sub_49FB60(__int64 a1)
{
  sub_484690(a1 + 208, 0LL);
  sub_484690(a1 + 112, 0LL);
  return sub_484690(a1 + 16, 0LL);
}
_QWORD *__fastcall sub_4A0050(_QWORD *a1, __int64 a2)
{
  sub_4A3CB0(a1);
  *a1 = off_979AD8;
  a1[13] = a2;
  return a1;
}
__int64 __fastcall sub_4D3D20(__int64 a1, __int64 a2, unsigned __int8 a3)
{
  __int64 v5; // rcx

  *(_QWORD *)a1 = a2;
  v5 = *(_QWORD *)(*(int *)(*(_QWORD *)a2 + 4LL) + a2 + 72);
  if ( v5 )
    (*(void (__fastcall **)(__int64))(*(_QWORD *)v5 + 8LL))(v5);
  *(_BYTE *)(a1 + 8) = sub_4D3BC0(*(_QWORD *)a1, a3);
  return a1;
}

Все эти функции имеют значение «Аргументы» 00000010. Первоначально я думал, что оно может представлять собой сумму размеров аргументов, но вычисления не совпадают. Что на самом деле представляет собой поле «Аргументы»?

【Функции коснитесь изображения】

Кроме того, что означает значение «Аргументы» для предоставленных примеров кода?

__int64 __fastcall sub_52AFD0(unsigned int **a1, unsinged int a2, __int64 a3)
{
    unsinged int v3;
    unsinged int v4;
    unsinged int v6;
    unsinged __int i;
    
    v6 =-1;
    for ( i = a2 / 8ui64; i; --i)
    {
      v3 = **a1 ^ v6;
      ++*a1;
      v4 = **a1;
      v6 = *(_DWORD *)(a3 + 4i64 * (v4 >> 24)));
    }
    return v6;
}

Как выглядит ассемблерный код? Я предполагаю, что значение аргументов — это то, что добавляется в RSP при выходе (не включая обратный адрес).

500 - Internal Server Error 03.09.2024 14:47

Пожалуйста, покажите сборку для некоторых из этих функций, а также макет стека той же функции (Правка->Функции->Переменные стека).

Andrey Turkin 03.09.2024 15:58

Поскольку я впервые использую Stack Overflow, я не знал, что здесь можно публиковать ответы. Извините за поздний ответ. Я предоставлю запрошенный вами ассемблерный код. !код_сборки ! код_декомплие ! функции_tap ! стек_переменные

jeong 03.09.2024 16:17

Было бы полезно добавить к вопросу, что это за архитектура. x86_64 (он же amd64)?

Ben Voigt 03.09.2024 17:11

Вы вручную вводили декомпилированные фрагменты кода в вопросе? Я скептически отношусь к тому, что IDA напишет unsigned с ошибкой как unsinged.

Ben Voigt 03.09.2024 20:58
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
5
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Значение в столбце «Аргументы», похоже, представляет собой пространство, зарезервированное для аргументов функции перед кадром стека функции (более высокие адреса стека). Следовательно, он не представляет общий размер всех аргументов функции, а только тех, которые прошли через стек. Спасибо Андрею Туркину за то, что указал на это в комментариях ниже.

Например, дизассемблируя /bin/awk в моей системе Linux x86-64 с IDA Free 8.4, я вижу следующую функцию:

__int64 __fastcall sub_47EC80(
        __int64 a1,
        unsigned int *a2,
        int a3,
        unsigned int a4,
        unsigned int a5,
        int a6,
        unsigned int a7)
{
    // ...
}

В столбце «Аргументы» отображается 00000004. Если посмотреть на разборку, то можно увидеть следующее:

.text:000000000047EC80 ; =============== S U B R O U T I N E =======================================
.text:000000000047EC80
.text:000000000047EC80
.text:000000000047EC80 ; __int64 __fastcall sub_47EC80(__int64, unsigned int *, int, unsigned int, unsigned int, int, unsigned int)
.text:000000000047EC80 sub_47EC80      proc near               ; CODE XREF: sub_47F350+2F↓p
.text:000000000047EC80                                         ; sub_47F500+6C5↓p
.text:000000000047EC80
.text:000000000047EC80 var_D0          = dword ptr -0D0h
   ... a bunch more var_XX here ...
.text:000000000047EC80 var_54          = dword ptr -54h
.text:000000000047EC80 ptr             = qword ptr -50h
.text:000000000047EC80 var_40          = qword ptr -40h
.text:000000000047EC80 arg_0           = dword ptr  8 
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ arg passed through stack
.text:000000000047EC80
.text:000000000047EC80 ; __unwind {
.text:000000000047EC80                 push    r15
.text:000000000047EC82                 mov     r15, rdi
.text:000000000047EC85                 push    r14
.text:000000000047EC87                 push    r13
.text:000000000047EC89                 push    r12
   ...

Обратите внимание, что единственная переменная, выделенная после указателя стека (с положительным смещением 8), — это arg_0. Это соответствует аргументу a7 в сигнатуре функции. В этом случае первые 6 аргументов передаются через регистры RDI, RSI, RDX, RCX, R8 и R9. Седьмой номер передается в стек.

Фактически, если я взгляну на внешние ссылки (нажмите X на имени функции), я увижу этот вызов:

.text:000000000047FBAD                 mov     [rsp+0E8h+var_E0], r10
.text:000000000047FBB2                 sub     rsp, 8
.text:000000000047FBB6                 mov     edx, [r15+4]
.text:000000000047FBBA                 mov     r9d, r13d
.text:000000000047FBBD                 push    9
.text:000000000047FBBF                 mov     r8d, ebp
.text:000000000047FBC2                 mov     rdi, r14
.text:000000000047FBC5                 call    sub_47EC80

Как видите, седьмой аргумент передается с помощью push 9. Несмотря на то, что инструкция push 9 помещает 8-байтовое значение в стек, функция, похоже, получает доступ к значению только с помощью 4-байтовых (dword) операций разыменования (или в любом случае обрабатывает его как 4-байтовое значение). Видимо, поэтому в столбце «Аргументы» отображается 00000004.

Аналогично, для этой другой функции:

__int64 __fastcall sub_44DC90(
        __int64 a1,
        const char *a2,
        int a3,
        __int64 a4,
        __int64 a5,
        void (__fastcall *a6)(_QWORD, _QWORD, _QWORD, _QWORD),
        __int64 a7,
        __int64 a8,
        char a9)
{
    // ...
}

Я вижу, что в столбце «Аргументы» отображается 00000011 (17), потому что __int64 a7, __int64 a8 и char a9 передаются через стек:

...
mov     rdi, 7FFFFFFFFFFFFFFFh
mov     [rsp+60h+var_48], rax
push    0
push    r12
push    rbp
call    r15
...

Изучение документации IDA

IDA имеет довольно хорошую встроенную документацию. Если вы поместите курсор в окно функции, а затем нажмете клавишу F1, документация откроется в новом окне. Вот как это выглядит на моей IDA Free 8.4.

Глядя на страницу «Окно функций» в документации, можно увидеть следующие поля:

  • имя функции
  • сегмент, содержащий функцию
  • смещение функции внутри сегмента
  • длина функции в байтах
  • размер (в байтах) локальных переменных + сохраняемые регистры
  • размер (в байтах) аргументов, передаваемых функции

Эта же страница документации также доступна онлайн здесь.

Судя по документу, столбец «Аргументы» должен представлять «размер аргументов, передаваемых функции». На YouTube-канале Hex-Rays также есть видео об окне «Функции» с пояснениями, а также говорится, что столбец «Аргументы» должен представлять «размер аргументов, передаваемых функции».

Эти описания кажутся слишком общими и не совсем точно отражают смысл столбца. Похоже, страницу документации следует обновить более четкими описаниями.

Те же рассуждения справедливы для 2-го и 3-го столбцов (Сегмент и Начало): столбец «Начало» определенно не представляет смещение внутри сегмента ELF, показанного в столбце «Сегмент» (хотя он показывает .text, который является разделом), а скорее абсолютный виртуальный адрес. Это может быть потому, что, как предлагает Бен Фойгт ниже, слово «сегмент» в документации для столбца «Сегмент» относится к двоичным (например, ELF) сегментам/разделам, но для столбца «Начало» оно может относиться к определенной архитектуре. сегменты, когда ЦП использует сегментированную модель памяти (например, сегментированный 16-битный реальный режим x86). Сбивает с толку.

P.S. для тех, кто голосует против: было бы неплохо оставить комментарий, объясняющий причину отрицательного голоса, если вы считаете, что этот ответ бесполезен, чтобы я мог его исправить/улучшить!

Marco Bonelli 03.09.2024 15:43

Большое спасибо за ваш искренний ответ.

jeong 03.09.2024 15:46

Вы правы в том, что это поле представляет собой размер стека области аргументов. IDA (x64) 7.7 показывает именно это. Например. поле вообще не заполнено для функции с 1 аргументом в двоичном файле Linux, но оно равно 8 для функции с 1 аргументом в двоичном файле Windows (где аргумент все еще передается в качестве аргумента, но затем сохраняется в теневое пространство). Я думаю, что более конкретно это поле представляет размер области стека над адресом возврата, как показано в окне стека функций.

Andrey Turkin 03.09.2024 15:55

@AndreyTurkin, теперь это имеет гораздо больше смысла. Хотя бывают странные случаи, это кажется правильным определением. Я обновлю свой ответ, спасибо!

Marco Bonelli 03.09.2024 17:03

"определенно не является "смещением функции внутри сегмента", а абсолютным виртуальным адресом функции... это одно и то же, если только не используется сегментированная архитектура памяти (например, 16-битная x86). "сегмент" != " раздел"

Ben Voigt 03.09.2024 17:08

Может ли значение «аргументы» иметь какое-либо отношение к соглашению о вызовах в регистрах сохранения вызывающего абонента и вызываемого абонента? Если определенное количество регистров доступно вызываемому объекту для использования в качестве нуля, даже если не передается никаких значимых данных, они все равно могут рассматриваться как хранилище аргументов для целей этого расчета.

Ben Voigt 03.09.2024 17:14

@BenVoigt Кажется, вы правы в том, что это смещение внутри сегмента (как в сегменте, определенном архитектурой в сегментированной модели памяти). Это имело бы больше смысла. Что сбивает с толку, так это то, что если вы посмотрите на то, что IDA называет «сегментом», вы увидите, что в столбце «Сегмент» указано .text... что является сегментом ELF. Итак, читая документ, мы видим «сегмент, содержащий функцию», за которым сразу следует «смещение функции внутри сегмента», что мне кажется совершенно неправильным/вводящим в заблуждение.

Marco Bonelli 03.09.2024 17:29

@BenVoigt, похоже, это не имеет особого отношения к регистрам, сохраненным вызывающим/вызывающим объектом, поскольку я вижу различные функции с нулевым столбцом «Аргументы», использующие сохраненные регистры вызывающего абонента для раздачи аргументов. Кажется, это связано только с пространством стека, непосредственно используемым вызывающей стороной для аргументов, как предположил выше Андрей.

Marco Bonelli 03.09.2024 17:31

Большое спасибо всем

jeong 03.09.2024 18:10

@MarcoBonelli: .text — это раздел, а не сегмент (в значении указателя/адреса). Даже в контексте ELF Похоже, что IDA неправильно это называет.

Ben Voigt 03.09.2024 18:15

У меня есть вопрос. Согласно MSDN, на x64 для аргументов используются 4 регистра и начиная с 5-го аргумента используется стек. Однако в вашем объяснении упоминается использование 6 регистров. Какой из них правильный?

jeong 03.09.2024 18:17

@jeong: MSDN документирует соглашение о вызовах Windows x86_64, которое не совсем совпадает с соглашением SYS V, на котором основан ответ (упоминание «SYS V» было удалено в одном из изменений).

Ben Voigt 03.09.2024 18:18

О, я был в замешательстве, потому что я привык к Windows. Спасибо.

jeong 03.09.2024 18:19

@BenVoigt Если да, то сложно ли оценить значение аргумента, только взглянув на декомпилированный код? Я использую 64-битную систему Windows. <br/> Пример декомпилированного исходного кода

jeong 03.09.2024 18:45

Я хотел бы получить значение locals на вкладке «Функция» в IDA.

jeong 03.09.2024 18:52

@jeong: Сигнатуры функций, сгенерированные IDA, очень полезны в этом отношении (гораздо более полезны, чем когда-либо был бы размер «аргументов», даже если бы он был правильным). Однако IDA не вывела указателей на структуры, и декомпиляция вашего примера включает в себя то, что для меня явно является доступом к членам структуры. *a1 и a3 оба являются указателями на неизвестные типы структур.

Ben Voigt 03.09.2024 20:55

Я думаю, что некоторые из показанных вами функций представляют собой вычисления CRC.

Ben Voigt 03.09.2024 20:58

@BenVoigt «.text — это раздел, а не сегмент», вы правы, я виноват, хотя обычно он соответствует 1:1 разделу RX, поэтому нередко можно услышать «текстовый раздел». Путаница с именами и описанием вещей IDA довольно дикая :')

Marco Bonelli 03.09.2024 22:32

@BenVoigt Спасибо, благодаря тебе я многому научился.

jeong 04.09.2024 03:37

Другие вопросы по теме