summaryrefslogtreecommitdiff
path: root/examples/encoded_strings/src/encoded_strings.cpp
blob: 62c89bef460d927099ab616f7d8ea2edd8dea1cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#define _CRT_SECURE_NO_WARNINGS
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <map>
#include <functional>
#include <vector>
#include "binaryninjaapi.h"
#include "highlevelilinstruction.h"

using namespace BinaryNinja;
using namespace std;


static Ref<CustomStringType> g_encodedStringType;


class EncodedStringRecognizer : public StringRecognizer
{
	typedef function<uint8_t(uint8_t, uint8_t)> Decoder;
	map<string, Decoder> m_decoders;

public:
	EncodedStringRecognizer() : StringRecognizer("encoded_strings")
	{
		// Initialize decoders
		m_decoders["xor_encoded"] = [](uint8_t encoded, uint8_t key) -> uint8_t {
			return encoded ^ key;
		};
		m_decoders["sub_encoded"] = [](uint8_t encoded, uint8_t key) -> uint8_t {
			return encoded - key;
		};
		m_decoders["add_encoded"] = [](uint8_t encoded, uint8_t key) -> uint8_t {
			return encoded + key;
		};
	}

	bool IsValidForType(HighLevelILFunction*, Type* type) override
	{
		if (!type || type->GetClass() != PointerTypeClass)
			return false;

		auto target = type->GetChildType();
		if (!target.GetValue())
			return false;

		// Check if any decoder attribute exists
		for (const auto& decoder : m_decoders)
		{
			if (target->GetAttribute(decoder.first).has_value())
				return true;
		}

		return false;
	}

	optional<DerivedString> RecognizeConstantPointer(
		const HighLevelILInstruction& instr, Type* type, int64_t val) override
	{
		if (!type || type->GetClass() != PointerTypeClass)
			return std::nullopt;

		auto target = type->GetChildType();
		if (!target)
			return std::nullopt;

		// Find the decoder and values
		vector<uint8_t> values;
		Decoder chosenDecoder;

		for (const auto& [name, decoder] : m_decoders)
		{
			if (auto attr = target->GetAttribute(name); attr.has_value())
			{
				// Parse hex string
				if (attr->length() % 2 != 0)
					return std::nullopt;

				for (size_t i = 0; i < attr->length(); i += 2)
				{
					string byteStr = attr->substr(i, 2);
					try
					{
						values.push_back((uint8_t)stoul(byteStr, nullptr, 16));
					}
					catch (...)
					{
						return std::nullopt;
					}
				}

				chosenDecoder = decoder;
				break;
			}
		}

		if (values.empty() || !chosenDecoder)
			return std::nullopt;

		bool encodedNull = target->GetAttribute("encoded_null").has_value();

		// Decode the string
		vector<uint8_t> resultBytes;
		size_t i = 0;
		Ref<BinaryView> view = instr.function->GetFunction()->GetView();

		while (true)
		{
			uint8_t byte;
			if (view->Read(&byte, val + i, 1) != 1)
				return std::nullopt;

			// Check for unencoded null terminator
			if (!encodedNull && byte == 0)
				break;

			// Decode the byte
			byte = chosenDecoder(byte, values[i % values.size()]);

			// Check for encoded null terminator
			if (byte == 0)
				break;

			resultBytes.push_back(byte);
			i++;
		}

		// Create the derived string
		DerivedStringLocation loc(DataBackedStringLocation, val, i);
		return DerivedString(string((char*)resultBytes.data(), resultBytes.size()), loc, g_encodedStringType);
	}
};


extern "C"
{
	BN_DECLARE_CORE_ABI_VERSION

	BINARYNINJAPLUGIN void CorePluginDependencies()
	{
	}

	BINARYNINJAPLUGIN bool CorePluginInit()
	{
		g_encodedStringType = CustomStringType::Register("Encoded", "", "_enc");
		StringRecognizer::Register(new EncodedStringRecognizer());
		return true;
	}
}