 |

08.02.2023, 20:07
|
|
Новичок
Регистрация: 13.02.2022
Сообщений: 12
С нами:
2236305
Репутация:
28
|
|
Шалом, это мой первый тред на борде.
И решил немного доработать старый исходник, который проходится по функциям IAT (Import Address Table), проверяя их на опкоды джампа, и брейкпоинтов x32dbg (int3, int 0x3, ud2), Ordinal, кстати, он не проверяет, но можете допилить за меня
Такой приём будет очень полезен против новичков в вашем лоадере, которые любят ставить бряки куда попало без предварительного динамического анализа защиты
Для незнающих скажу, что если ваша функция накрыта виртуализацией кода, которая за собой как бонус будет вызывать функцию по своему функцию и и на этот адрес нет никаких других внешних вызовов в вашей программе, то этот чек пользователь спокойно пройдет, поскольку данной функции не будет в IAT.
Вот и сам исходник:
IATScan.hpp:
Код:
#pragma once
#include
#include
#include
#include
namespace
Engine
{
struct
S_CorruptedFunction
{
std
::
string m_cModuleName
;
std
::
string m_cFunctionName
;
std
::
uintptr_t m_pAddress
;
S_CorruptedFunction
(
std
::
string cModule
,
std
::
string cFunc
,
std
::
uintptr_t pAddress
)
:
m_cModuleName
(
std
::
move
(
cModule
)
)
,
m_cFunctionName
(
std
::
move
(
cFunc
)
)
,
m_pAddress
(
std
::
move
(
pAddress
)
)
{
}
}
;
inline
BYTE bInt3Breakpoint
=
0xCC
;
inline
BYTE bJumpOpcode
=
0xE9
;
inline
WORD wUd2Breakpoint
=
0x0B0F
;
inline
WORD wInt3Breakpoint
=
0x03CD
;
inline
std
::
vector
m_cCorruptedFunctions
{
}
;
void
OutputCorruptedFunctions
(
)
;
void
AddFunction
(
const
S_CorruptedFunction
&
cCorruptedFunctions
)
;
bool
IATScan
(
)
;
}
IATScan.cpp:
Код:
#include "IATScan.hpp"
void
Engine
::
OutputCorruptedFunctions
(
)
{
if
(
m_cCorruptedFunctions
.
empty
(
)
)
{
printf
(
"[~] No corrupted functions found!\n"
)
;
return
;
}
for
(
const
auto
&
Iterator
:
m_cCorruptedFunctions
)
printf
(
"[!] Module: %s\tFunction: %s\tAddress: 0x%p\n"
,
Iterator
.
m_cModuleName
.
c_str
(
)
,
Iterator
.
m_cFunctionName
.
c_str
(
)
,
Iterator
.
m_pAddress
)
;
}
void
Engine
::
AddFunction
(
const
S_CorruptedFunction
&
cCorruptedFunctions
)
{
m_cCorruptedFunctions
.
push_back
(
cCorruptedFunctions
)
;
}
bool
Engine
::
IATScan
(
)
{
LPVOID lpBaseAddress
=
(
LPVOID
)
GetModuleHandle
(
NULL
)
;
PIMAGE_DOS_HEADER pDosHeader
;
PIMAGE_NT_HEADERS pNtHeader
;
IMAGE_OPTIONAL_HEADER pOptionalHeader
;
IMAGE_DATA_DIRECTORY pImportDirectory
;
DWORD dwStartRVA
;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor
;
pDosHeader
=
(
PIMAGE_DOS_HEADER
)
lpBaseAddress
;
if
(
pDosHeader
->
e_magic
!=
IMAGE_DOS_SIGNATURE
)
return
false
;
pNtHeader
=
(
PIMAGE_NT_HEADERS
)
(
(
DWORD_PTR
)
lpBaseAddress
+
pDosHeader
->
e_lfanew
)
;
if
(
pNtHeader
->
Signature
!=
IMAGE_NT_SIGNATURE
)
return
false
;
pOptionalHeader
=
pNtHeader
->
OptionalHeader
;
pImportDirectory
=
pOptionalHeader
.
DataDirectory
[
IMAGE_DIRECTORY_ENTRY_IMPORT
]
;
dwStartRVA
=
pImportDirectory
.
VirtualAddress
;
pImportDescriptor
=
(
PIMAGE_IMPORT_DESCRIPTOR
)
(
(
DWORD_PTR
)
lpBaseAddress
+
dwStartRVA
)
;
if
(
pImportDescriptor
==
NULL
)
return
false
;
DWORD dwIndex
=
-
1
;
while
(
pImportDescriptor
[
++
dwIndex
]
.
Characteristics
!=
0
)
{
PIMAGE_THUNK_DATA pOriginalFirstThunk
;
PIMAGE_THUNK_DATA pFirstThunk
;
char
*
pDllName
=
(
char
*
)
(
(
DWORD_PTR
)
lpBaseAddress
+
pImportDescriptor
[
dwIndex
]
.
Name
)
;
HMODULE hModule
=
GetModuleHandleA
(
pDllName
)
;
pOriginalFirstThunk
=
(
PIMAGE_THUNK_DATA
)
(
(
DWORD_PTR
)
lpBaseAddress
+
pImportDescriptor
[
dwIndex
]
.
OriginalFirstThunk
)
;
pFirstThunk
=
(
PIMAGE_THUNK_DATA
)
(
(
DWORD_PTR
)
lpBaseAddress
+
pImportDescriptor
[
dwIndex
]
.
FirstThunk
)
;
if
(
pOriginalFirstThunk
==
nullptr
||
pFirstThunk
==
nullptr
)
return
false
;
while
(
pOriginalFirstThunk
->
u1
.
AddressOfData
)
{
if
(
!
(
pOriginalFirstThunk
->
u1
.
Ordinal
&
IMAGE_ORDINAL_FLAG
)
)
{
PIMAGE_IMPORT_BY_NAME pImageImport
=
(
PIMAGE_IMPORT_BY_NAME
)
(
(
LPBYTE
)
lpBaseAddress
+
pOriginalFirstThunk
->
u1
.
AddressOfData
)
;
auto
pFn
=
GetProcAddress
(
hModule
,
(
LPCSTR
)
pImageImport
->
Name
)
;
if
(
(
*
(
BYTE
*
)
pFn
==
bInt3Breakpoint
||
*
(
BYTE
*
)
pFn
==
bJumpOpcode
)
||
(
*
(
WORD
*
)
pFn
==
wUd2Breakpoint
||
*
(
WORD
*
)
pFn
==
wInt3Breakpoint
)
)
{
Engine
::
AddFunction
(
S_CorruptedFunction
(
std
::
string
(
pDllName
)
,
std
::
string
(
pImageImport
->
Name
)
,
(
std
::
uintptr_t
)
pFn
)
)
;
}
}
pFirstThunk
++
;
pOriginalFirstThunk
++
;
}
}
return
true
;
}
Пример его использования:
Entry.cpp:
Код:
#include "IATScan.hpp"
int
main
(
)
{
printf
(
"t.me/colby5engineering\n\n"
)
;
if
(
Engine
::
IATScan
(
)
==
true
)
Engine
::
OutputCorruptedFunctions
(
)
;
else
printf
(
"[-] Failed to scan iat :(\n"
)
;
std
::
cin
.
get
(
)
;
return
0
;
}
Результат использования функции:
1675872223136.pngcolby57 · 8 Фев 2023 в 19:07' data-fancybox="lb-post-1252723" data-lb-caption-extra-html="" data-lb-sidebar-href="" data-single-image="1" data-src="https://www.blast.hk/attachments/189178/" style="cursor: pointer;" title="1675872223136.png">
Также забыл сказать, что функция _initialize_narrow_environment будет находится в списке, поскольку первый её байт - это 0xE9. Для неё можно спокойно сделать проверку.
Полный исходный код находится на гитхабе: https://github.com/colby57/IAT-Scanner
Всем пока!
|
|
|

08.02.2023, 20:12
|
|
Познающий
Регистрация: 29.03.2022
Сообщений: 99
С нами:
2174010
Репутация:
33
|
|
нус, тема бомба, добро пожаловать
|
|
|

08.02.2023, 20:16
|
|
Новичок
Регистрация: 08.02.2023
Сообщений: 2
С нами:
1717811
Репутация:
3
|
|
Годно
|
|
|

09.02.2023, 00:13
|
|
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами:
4483143
Репутация:
183
|
|
Много чего не учтено. По хорошему тут чуть ли не эмулятор прикручивать надо. Тот же long jmp игнорируется(ff 25).
Можно например сделать вообще что-нибудь типа
Код:
Код:
xor eax, eax
jno code
code:
int 3
Но против нубов спасет, да. Только по хорошему сюда еще проверку региона на PAGE GUARD прикрутить
|
|
|

09.02.2023, 03:57
|
|
Познавший АНТИЧАТ
Регистрация: 29.09.2018
Сообщений: 1,292
С нами:
4012500
Репутация:
138
|
|
О колби на бластхак пришел, ку
|
|
|

09.02.2023, 08:31
|
|
Новичок
Регистрация: 13.02.2022
Сообщений: 12
С нами:
2236305
Репутация:
28
|
|
Сообщение от kin4stat
Можно например сделать вообще что-нибудь типа
Пример неуместный
Если ты ещё не понял, то есть разница между бряком, который вписываешь ты, и бряком который ставит непосредственно сам дебаггер.
В твоём примере я вижу, что бряк вписываешь именно ты
У дебаггера есть 4 вида бряков: хардвейр в виде 4 штук, int3, ud2 и int 0x3, который как раз ты и поставил.
При выполнении данного кода ты поймаешь краш с исключением EXCEPTION_BREAKPOINT, поскольку отладчик будет обрабатывать только опкоды бряков, которые он сам выставил. Можешь конечно сам модифицировать отладчик, и вместо условного int 0x3, который ты показал можешь поменять на тот асм-код, который ты решил предоставить в своём примере, но произойдет нечто страшное))
Да и где тут вообще восстановление регистра eax? Ты просто контекст ломаешь, а если у меня в eax важный аргумент лежит с поинтером, который ты затёр?
Раз уже показываешь пример, то показывай правильный, ака:
Код:
Код:
push eax
xor eax, eax
jno code
code:
nop
pop eax
Сообщение от kin4stat
Тот же long jmp игнорируется(ff 25).
Никто не спорит, ведь в теме я упомянул как раз о том, что мой исходник это лишь пример того, как можно обнаруживать бряки или релативный джамп, и ещё упомянул, что ничего не мешает добавлять свои детекты
Сообщение от kin4stat
Но против нубов спасет, да. Только по хорошему сюда еще проверку региона на PAGE GUARD прикрутить
Опять же, ответ выше
Можно долго спорить о том, чего у меня не хватает в коде, и какие меры предпринимать по обходу этого. Сам я мог бы это обойти как раз 1 хардвейр бряком на любую функцию из IAT, но тем не менее я уже объяснил, что против новичков такое сработает, да и люди в основном абузят MinHook и в x86 и в x64 в наглую, где как раз в начале хукнутой функции будет установлен угадай что? Релативный джамп, т.е. первый байт у тебя будет 0xE9  Поэтому в любом случае даже если не улучшать детекты в моём исходнике, то детектов будет предостаточно, чтобы отсеивать новичков.
|
|
|

09.02.2023, 20:15
|
|
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами:
4483143
Репутация:
183
|
|
Сообщение от colby57
При выполнении данного кода ты поймаешь краш с исключением EXCEPTION_BREAKPOINT, поскольку отладчик будет обрабатывать только опкоды бряков, которые он сам выставил.
От отладчика все же зависит. Ну и кстати этот эксепшен скипается легко
Сообщение от colby57
Да и где тут вообще восстановление регистра eax? Ты просто контекст ломаешь, а если у меня в eax важный аргумент лежит с поинтером, который ты затёр?
Раз уже показываешь пример, то показывай правильный, ака:
Это псевдокод все же был, а не реальный пример. Очевидно что регистр не сохранен.
|
|
|

11.02.2023, 12:10
|
|
Новичок
Регистрация: 13.02.2022
Сообщений: 12
С нами:
2236305
Репутация:
28
|
|
Сообщение от kin4stat
От отладчика все же зависит. Ну и кстати этот эксепшен скипается легко
чего?)))
Нет, ну если ты написал свой дебаггер, который по всем параметрам превосходит x64dbg, который обновляют часто, то тут прям моё увожение, однако я повторяю тебе еще раз, x64dbg на сегодняшний момент является самым стабильным и актуальным отладчиком в юзермоде, но тем не менее, хендлить бряки, которые ставят удаленно с дллки или в самом дебаггере прописывая инт3 в ручную он не умеет, что приводит к... о боже мой!
Первая строка это то, как x64dbg сам ставит дебаггер по кнопочке F2, а другие строчки это попытки дебаггера обработать инт3, который пренадлежит не ему
Да и что значит твоё "легко скипается"? Понятное дело, что если ты свой вех поставишь, то сможешь сам проскипать, только я не понимаю к чему это мне было писать)
Сообщение от kin4stat
Это псевдокод все же был, а не реальный пример. Очевидно что регистр не сохранен.
Ну, раз ты решил докапываться до моей идеи, то и я буду преследовать ту же цель в твоих ответах мне
Бля, мужик..
Если пытаешься меня чему-то учить (будучи зная меньше чем я), то хотя бы выписывай правильно примеры, отговариваться по типу "это просто псевдокод" не нужно, если бы в дебаггере вместо инт3 юзался твой код, бедные реверсеры бы каждый день тебе отписывали с баг-репортом, что контекст их программы каким-то чудом умудрился сломаться...
Найдешь к чему ещё прикопаться, или закончим наш чудесный диалог?
|
|
|

12.02.2023, 00:07
|
|
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами:
4483143
Репутация:
183
|
|
Сообщение от colby57
чего?)))
Нет, ну если ты написал свой дебаггер, который по всем параметрам превосходит x64dbg, который обновляют часто, то тут прям моё увожение, однако я повторяю тебе еще раз, x64dbg на сегодняшний момент является самым стабильным и актуальным отладчиком в юзермоде, но тем не менее, хендлить бряки, которые ставят удаленно с дллки или в самом дебаггере прописывая инт3 в ручную он не умеет, что приводит к... о боже мой!
Первая строка это то, как x64dbg сам ставит дебаггер по кнопочке F2, а другие строчки это попытки дебаггера обработать инт3, который пренадлежит не ему
Да и что значит твоё "легко скипается"? Понятное дело, что если ты свой вех поставишь, то сможешь сам проскипать, только я не понимаю к чему это мне было писать)
Или можно просто Ctrl+F8 нажать. Тоже работает.
Думаю вопрос исчерпан.
Сообщение от colby57
Ну, раз ты решил докапываться до моей идеи, то и я буду преследовать ту же цель в твоих ответах мне
Бля, мужик..
Если пытаешься меня чему-то учить (будучи зная меньше чем я)
Давай не будем прибегать к оценке чужих знаний. Это как минимум некультурно.
Я тоже мог доебаться до каждой строки кода у тебя, но как ты видишь я этого не сделал.
Сообщение от colby57
если бы в дебаггере вместо инт3 юзался твой код, бедные реверсеры бы каждый день тебе отписывали с баг-репортом, что контекст их программы каким-то чудом умудрился сломаться...
Я тебе просто указал на неполноценность твоего решения. Это не general-purpose решение. В этом моя основная претензия.
Как минимум сканер сломается если брейкпоинт ставить не на первую инструкцию функции. Ну и хотя бы на ff25 проверку добавил бы.
|
|
|

12.02.2023, 03:54
|
|
Новичок
Регистрация: 11.02.2023
Сообщений: 4
С нами:
1713832
Репутация:
13
|
|
Сообщение от kin4stat
Я тебе просто указал на неполноценность твоего решения. Это не general-purpose решение. В этом моя основная претензия.
Как минимум сканер сломается если брейкпоинт ставить не на первую инструкцию функции. Ну и хотя бы на ff25 проверку добавил бы.
Давай не будем прибегать к оценке чужих знаний -> Много чего не учтено. По хорошему тут чуть ли не эмулятор прикручивать надо.
Тот же long jmp игнорируется(ff 25) -> Ну и хотя бы на ff25 проверку добавил бы.
Простите, но это больше напоминает: "Ты должен добавить, но у меня точно нет претензий и из-за этого я прошу 2 раза добавить проверку на ff 25".
Сообщение от kin4stat
Или можно просто Ctrl+F8 нажать. Тоже работает.
Думаю вопрос исчерпан.
Я не совсем понимаю, зачем вы показали в одношаговой трассировке обработку INT3 для программы (параметры-> ядро -> пропускать INT3 при пошаговом выполнении). Да, некоторые ошибки можно пропустить (проглотить исключения/пропустить исключения).
Опять же смотрим, как тот же x64dbg обрабатывает это.
Я не хочу смотреть и продолжать этот бессмысленный спор. Давайте его закончим со следующими мыслями:
1)Это просто пример.
Давайте не будем утверждать, что те же некоторые отсталые AV хукают в DLL Api/NtApi или что нужно больше детектов.
Это сделано для новичкови мы не будем говорить 1000 раз НО.
2)Не надо доказывать, что я умнее тебя и продолжать из-за этого спор + при этом докапываться при этом к любому слову.
Как-то Frostiest сказал умную, но простую мысль ~его слова: "Вам не нужно быть гением, чтобы общаться из-за этого с гениями".
|
|
|
|
 |
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|