#ifndef LLVM_TRANSFORMS_UTILS_OBFUSCATION_H
#define LLVM_TRANSFORMS_UTILS_OBFUSCATION_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MathExtras.h"
namespace llvm {
class Module;
namespace obfuscate {
class Obfuscator {
using MapTy = StringMap<StringRef, BumpPtrAllocator &>;
BumpPtrAllocator Alloc;
bool Reverse = false;
MapTy ForwardMap;
MapTy ReverseMap;
MapTy TyForwardMap;
protected:
virtual StringRef obfuscateImpl(StringRef) = 0;
virtual StringRef obfuscateTypeNameImpl(StringRef S) {
return obfuscateImpl(S);
}
char *allocateString(unsigned Length) {
assert(Length > 0 && "no length?");
char *P = (char *)Alloc.Allocate(Length + 1, 1);
P[Length] = '\0';
return P;
}
virtual ~Obfuscator() {}
public:
Obfuscator(bool Reversible = false)
: Alloc(), Reverse(Reversible), ForwardMap(64, Alloc), ReverseMap(Alloc),
TyForwardMap(64, Alloc) {}
StringRef obfuscate(StringRef Src) {
assert(Src.size() && "passed in empty string");
if (ForwardMap.count(Src))
return ForwardMap.lookup(Src);
auto Res = obfuscateImpl(Src);
ForwardMap[Src] = Res;
if (Reverse) {
auto OldName = copyString(Src);
assert((ReverseMap.lookup(Res) == StringRef() ||
ReverseMap.lookup(Res) == Src) &&
"Already entered in, and as a different source. Collision?");
ReverseMap.insert({Res, OldName});
}
return Res;
}
char *copyString(StringRef S) {
auto Ret = allocateString(S.size());
std::copy(S.begin(), S.end(), Ret);
return Ret;
}
StringRef obfuscateTypeName(StringRef Src) {
assert(Src.size() && "passed in empty string");
if (TyForwardMap.count(Src))
return TyForwardMap.lookup(Src);
auto Res = obfuscateTypeNameImpl(Src);
TyForwardMap[Src] = Res;
return Res;
}
void obfuscateModule(Module &M,
std::function<bool(Value &)> preserve);
bool providesReverseMapping() const { return Reverse; }
StringRef getReverseMapping(StringRef Obf) const {
assert(providesReverseMapping() && "doesn't provide a reverse mapping");
assert(Obf != ReverseMap.lookup(Obf));
return ReverseMap.lookup(Obf);
}
const MapTy &reverseMap() const {
assert(providesReverseMapping() && "doesn't provide a reverse mapping");
return ReverseMap;
}
virtual void writeReverseMap(raw_ostream &OS) {
for (auto &STE : reverseMap())
OS << STE.getKey() << ":" << STE.getValue() << "\n";
}
BumpPtrAllocator &getAllocator() { return Alloc; }
private:
Obfuscator(const Obfuscator &) = delete;
Obfuscator &operator = (const Obfuscator &) = delete;
virtual void anchor() = 0;
};
class Rot13Obfuscator : public Obfuscator {
using Obfuscator::Obfuscator;
char rot13(char C) {
if (C >= 'A' && C <= 'Z')
return ((C - 'A' + 13) % 26) + 'A';
if (C >= 'a' && C <= 'z')
return ((C - 'a' + 13) % 26) + 'a';
return C;
}
virtual void anchor() override;
protected:
StringRef obfuscateImpl(StringRef S) override {
char *NewStr = allocateString(S.size());
assert(NewStr[S.size()] == '\0' && "not null terminated");
for (unsigned i = 0; i < S.size(); ++i)
NewStr[i] = rot13(S[i]);
return {NewStr, S.size()};
}
StringRef obfuscateTypeNameImpl(StringRef S) override {
return obfuscateImpl(S);
}
};
class IncrementObfuscator : public Obfuscator {
StringRef Pre;
StringRef Suf;
StringRef TyPre;
unsigned Num = 0;
unsigned TyNum = 0;
bool ShouldPad;
virtual void anchor() override;
public:
IncrementObfuscator(bool Reversible = false, bool Pad = false,
StringRef Prefix = "__hidden#", StringRef Suffix = "_",
StringRef TypePrefix = "__type_hidden#")
: Obfuscator(Reversible), Pre(copyString(Prefix)),
Suf(copyString(Suffix)), TyPre(TypePrefix), ShouldPad(Pad) {}
void writeReverseMap(raw_ostream &OS) override;
protected:
StringRef obfuscateImpl(StringRef S) override {
SmallString<128> NextVal;
raw_svector_ostream OS(NextVal);
if (S.startswith("\01L") || S.startswith("\01l"))
OS << S.substr(0, StringRef("\01l").size());
OS << Pre << Num++ << Suf;
OS.flush();
if (ShouldPad && S.size() > NextVal.size())
NextVal.append(NextPowerOf2(S.size()) - NextVal.size(), '_');
return copyString(OS.str());
}
StringRef obfuscateTypeNameImpl(StringRef S) override {
SmallString<128> NextVal;
raw_svector_ostream OS(NextVal);
OS << TyPre << TyNum++;
OS.flush();
return copyString(OS.str());
}
private:
unsigned findIndex(StringRef Key) {
assert(Key.size() > Pre.size() + Suf.size() && "invalid key");
size_t Offset = Pre.size();
if (Key.startswith("\01L") || Key.startswith("\01l"))
Offset += 2;
const char *NumStart = Key.data() + Offset;
size_t Sz = Key.rfind(Suf);
assert(Sz != StringRef::npos && "out of bounds");
unsigned long long Ret;
bool Error = getAsUnsignedInteger({NumStart, Sz - Offset}, 10, Ret);
(void) Error;
assert(!Error && "failed to convert to integer");
return Ret;
};
};
}
}
#endif // LLVM_TRANSFORMS_UTILS_OBFUSCATION_H