ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Сканирование функции на брейкпоинты и хуки (https://forum.antichat.xyz/showthread.php?t=1467435)

colby57 08.02.2023 20:07

Шалом, это мой первый тред на борде.

И решил немного доработать старый исходник, который проходится по функциям 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">
https://forum.antichat.xyz/attachments/28252723/

Также забыл сказать, что функция _initialize_narrow_environment будет находится в списке, поскольку первый её байт - это 0xE9. Для неё можно спокойно сделать проверку.

Полный исходный код находится на гитхабе: https://github.com/colby57/IAT-Scanner

Всем пока!

digitalpurple 08.02.2023 20:12

нус, тема бомба, добро пожаловать

arkwhtp 08.02.2023 20:16

Годно

kin4stat 09.02.2023 00:13

Много чего не учтено. По хорошему тут чуть ли не эмулятор прикручивать надо. Тот же long jmp игнорируется(ff 25).

Можно например сделать вообще что-нибудь типа

Код:





Код:

xor eax, eax
jno code

code:
int 3



Но против нубов спасет, да. Только по хорошему сюда еще проверку региона на PAGE GUARD прикрутить

F0RQU1N and 09.02.2023 03:57

О колби на бластхак пришел, ку

colby57 09.02.2023 08:31

Цитата:

Сообщение от 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 :) Поэтому в любом случае даже если не улучшать детекты в моём исходнике, то детектов будет предостаточно, чтобы отсеивать новичков.

kin4stat 09.02.2023 20:15

Цитата:

Сообщение от colby57

При выполнении данного кода ты поймаешь краш с исключением EXCEPTION_BREAKPOINT, поскольку отладчик будет обрабатывать только опкоды бряков, которые он сам выставил.

От отладчика все же зависит. Ну и кстати этот эксепшен скипается легко

Цитата:

Сообщение от colby57

Да и где тут вообще восстановление регистра eax? Ты просто контекст ломаешь, а если у меня в eax важный аргумент лежит с поинтером, который ты затёр?
Раз уже показываешь пример, то показывай правильный, ака:

Это псевдокод все же был, а не реальный пример. Очевидно что регистр не сохранен.

colby57 11.02.2023 12:10

Цитата:

Сообщение от kin4stat

От отладчика все же зависит. Ну и кстати этот эксепшен скипается легко

чего?)))

Нет, ну если ты написал свой дебаггер, который по всем параметрам превосходит x64dbg, который обновляют часто, то тут прям моё увожение, однако я повторяю тебе еще раз, x64dbg на сегодняшний момент является самым стабильным и актуальным отладчиком в юзермоде, но тем не менее, хендлить бряки, которые ставят удаленно с дллки или в самом дебаггере прописывая инт3 в ручную он не умеет, что приводит к... о боже мой!

https://forum.antichat.xyz/attachments/28254021/

Первая строка это то, как x64dbg сам ставит дебаггер по кнопочке F2, а другие строчки это попытки дебаггера обработать инт3, который пренадлежит не ему

Да и что значит твоё "легко скипается"? Понятное дело, что если ты свой вех поставишь, то сможешь сам проскипать, только я не понимаю к чему это мне было писать)

Цитата:

Сообщение от kin4stat

Это псевдокод все же был, а не реальный пример. Очевидно что регистр не сохранен.

Ну, раз ты решил докапываться до моей идеи, то и я буду преследовать ту же цель в твоих ответах мне

Бля, мужик..

Если пытаешься меня чему-то учить (будучи зная меньше чем я), то хотя бы выписывай правильно примеры, отговариваться по типу "это просто псевдокод" не нужно, если бы в дебаггере вместо инт3 юзался твой код, бедные реверсеры бы каждый день тебе отписывали с баг-репортом, что контекст их программы каким-то чудом умудрился сломаться...

Найдешь к чему ещё прикопаться, или закончим наш чудесный диалог?

kin4stat 12.02.2023 00:07

Цитата:

Сообщение от colby57

чего?)))
Нет, ну если ты написал свой дебаггер, который по всем параметрам превосходит x64dbg, который обновляют часто, то тут прям моё увожение, однако я повторяю тебе еще раз, x64dbg на сегодняшний момент является самым стабильным и актуальным отладчиком в юзермоде, но тем не менее, хендлить бряки, которые ставят удаленно с дллки или в самом дебаггере прописывая инт3 в ручную он не умеет, что приводит к... о боже мой!

https://forum.antichat.xyz/attachments/28254576/

Первая строка это то, как x64dbg сам ставит дебаггер по кнопочке F2, а другие строчки это попытки дебаггера обработать инт3, который пренадлежит не ему

Да и что значит твоё "легко скипается"? Понятное дело, что если ты свой вех поставишь, то сможешь сам проскипать, только я не понимаю к чему это мне было писать)

Или можно просто Ctrl+F8 нажать. Тоже работает.

Думаю вопрос исчерпан.

Цитата:

Сообщение от colby57

Ну, раз ты решил докапываться до моей идеи, то и я буду преследовать ту же цель в твоих ответах мне

Бля, мужик..
Если пытаешься меня чему-то учить (будучи зная меньше чем я)

Давай не будем прибегать к оценке чужих знаний. Это как минимум некультурно.

Я тоже мог доебаться до каждой строки кода у тебя, но как ты видишь я этого не сделал.

Цитата:

Сообщение от colby57

если бы в дебаггере вместо инт3 юзался твой код, бедные реверсеры бы каждый день тебе отписывали с баг-репортом, что контекст их программы каким-то чудом умудрился сломаться...

Я тебе просто указал на неполноценность твоего решения. Это не general-purpose решение. В этом моя основная претензия.

Как минимум сканер сломается если брейкпоинт ставить не на первую инструкцию функции. Ну и хотя бы на ff25 проверку добавил бы.

Ahora57 12.02.2023 03:54

Цитата:

Сообщение от 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 сказал умную, но простую мысль ~его слова: "Вам не нужно быть гением, чтобы общаться из-за этого с гениями".


Время: 12:33