Compare commits

..

2 Commits

Author SHA1 Message Date
9fd9e66340 hooking engines 2020-02-26 22:20:55 +01:00
8f73fcf829 add pics from old blog 2019-11-11 18:56:51 +01:00
4 changed files with 73 additions and 2 deletions

View File

@@ -7,7 +7,7 @@ draft: false
I wanted to get back into ARM assembler so I wrote my own strlen. And then I looked at the strlen() glibc uses and did not understand I wanted to get back into ARM assembler so I wrote my own strlen. And then I looked at the strlen() glibc uses and did not understand
a single thing. So I sat down and figured it out. a single thing. So I sat down and figured it out.
XXX IMG HERE XXX ![side by side comparsion](https://wacked.codes/img/arm-glibc-strlen/strlen-side-by-side.png)
On the left you see a flow diagram of the building blocks of my naive implementation. On the right you see glibc's. You might On the left you see a flow diagram of the building blocks of my naive implementation. On the right you see glibc's. You might
notice that it is more complex. (How much faster it is, and which optimization exactly makes it fast is an interesting topic. notice that it is more complex. (How much faster it is, and which optimization exactly makes it fast is an interesting topic.
@@ -22,7 +22,7 @@ The first thing I noticed about the inner loop is that it is unrolled. That is a
because strlen does not clearly unroll as the input is cleanly divisible by word size. So on the end of every basic block there because strlen does not clearly unroll as the input is cleanly divisible by word size. So on the end of every basic block there
is a check which skips out of the loop and to the end where the result is calculated and returned. is a check which skips out of the loop and to the end where the result is calculated and returned.
XXX IMG HERE XXX ![side by side comparsion](https://wacked.codes/img/arm-glibc-strlen/strlen-loop.png)
The basic blocks are basically identical. First the registers r2 and r3 are populated with the next two words to be checked for The basic blocks are basically identical. First the registers r2 and r3 are populated with the next two words to be checked for
the null byte. Now r2 and r3 each contain one word (i.e. 4 bytes). How do you check whether there is a null byte *somewhere* in them? the null byte. Now r2 and r3 each contain one word (i.e. 4 bytes). How do you check whether there is a null byte *somewhere* in them?

View File

@@ -0,0 +1,71 @@
---
title: "Hooking Engine Deatmatch"
description: "Evaluating various hooking engines, putting them against pathologically hard to hook functions"
date: 2020-02-26T22:00:00+01:00
draft: false
---
For the full code see the [git repo](https://vcs.wacked.codes/wacked/hook_tests).
Introduction
============
This project aims to give a simple overview on how good various x64 hooking
engines (on windows) are. I'll try to write various functions, that are hard to
patch and then see how each hooking engine does.
I'll test:
* [EasyHook](https://easyhook.github.io/)
* [PolyHook](https://github.com/stevemk14ebr/PolyHook)
* [MinHook](https://www.codeproject.com/Articles/44326/MinHook-The-Minimalistic-x-x-API-Hooking-Libra)
* [Mhook](http://codefromthe70s.org/mhook24.aspx)
(I'd like to test detours, but I'm not willing to pay for it. So that isn't
tested :( )
There are multiple things that make hooking difficult. Maybe you want to patch
while the application is running -- in that case you might get race conditions,
as the application is executing your half finished hook. Maybe the software has
some self protection features (or other software on the system provides that,
e.g. Trustee Rapport)
Evaluating how the hooking engines stack up against that is not the goal here.
Neither are non-functional criteria, like how fast it is or how much memory it
needs for each hook. This is just about the challenges the function to be
hooked itself poses.
Namely:
* Are jumps relocated?
* What about RIP adressing?
* If there's a loop at the beginning / if it's a tail recurisve function, does
the hooking engine handle it?
* How good is the dissassembler, how many instructions does it know?
* Can it hook already hooked functions?
At first I will give a short walk through of the architecture, then quickly go
over the test cases. After that come the results and an evaluation for each
engine.
I think I found a flaw in all of them; I'll publish a small POC which should at
least detect the existence of problematic code.
**A word of caution**: my results are worse than expected, so do assume I have
made a mistake in using the libraries. I went into this expecting that some
engines at least would try to detect e.g. the loops back into the first few
bytes. But none did? That's gotta be wrong.
**Another word of caution**: parts of this are rushed and/or ugly. Please
double check parts that seem suspicious. And I'd love to get patches, even for
the most trivial things -- spelling mistakes? Yes please.
Result
========
| Name|Small|Branch|RIP Relative|AVX|RDRAND|Loop|TailRec|
|----------|-----|------|------------|---|------|----|-------|
| PolyHook| X | X | X | X | | | |
| MinHook| X | X | X | | | | X |
| MHook| | | X | | | | |

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB