add internal efiensctf 2020
This commit is contained in:
parent
9d4d0b4fd7
commit
6e72946689
BIN
creator/internal-efiensctf-2020/Offsets
Normal file
BIN
creator/internal-efiensctf-2020/Offsets
Normal file
Binary file not shown.
17
creator/internal-efiensctf-2020/README.md
Normal file
17
creator/internal-efiensctf-2020/README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
I created 2 challenges for the Internal Efiens CTF 2020
|
||||||
|
|
||||||
|
- Nodejs
|
||||||
|
- Offsets
|
||||||
|
|
||||||
|
For the nodejs challenge, I modified the code of nodejs to add 2 functions, one at js layer and one at C++ layer. Both can be accessed from the global environment of Node by `require('flag')`.
|
||||||
|
|
||||||
|
The js code is a simple state machine, by reading the source code it is trivial to find the flag.
|
||||||
|
|
||||||
|
The C++ code is harder to read though. I give pointers by printing out debug information, thus it is trivial to find the function. Then a simple xor operation is done on the input array, we can easily read the key and encrypted value to decrypt the flag.
|
||||||
|
|
||||||
|
There is a mistake when I made this challenge, I built the binary with a debug statement to print the expected character after the xor.
|
||||||
|
|
||||||
|
|
||||||
|
Offsets challenge are made using LLVM and O-LLVM. I added another transform operation. This transform converts `array[i]` in assembly into `array[f()]` where `f() = i`. In this challenge I apply simple math and can be read through easily. One can use angr to solve this challenge. For more information, read `StructOffset.cpp`.
|
||||||
|
|
||||||
|
The source code for the challenge is lost, try to solve with only the binary.
|
255
creator/internal-efiensctf-2020/StructOffset.cpp
Normal file
255
creator/internal-efiensctf-2020/StructOffset.cpp
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/Instructions.h"
|
||||||
|
#include "llvm/IR/Constants.h"
|
||||||
|
#include "llvm/IR/Value.h"
|
||||||
|
#include "llvm/IR/InstrTypes.h"
|
||||||
|
#include "llvm/IR/DataLayout.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
|
#include "CryptoUtils.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "structoffset"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct StructOffsetJni : public FunctionPass {
|
||||||
|
static char ID;
|
||||||
|
StructOffsetJni() : FunctionPass(ID) {}
|
||||||
|
|
||||||
|
bool runOnFunction(Function& F) override {
|
||||||
|
int var_count = 15; // a random number for debugging in IR
|
||||||
|
llvm::cryptoutils->prng_seed();
|
||||||
|
std::stack<Instruction*> old_gets;
|
||||||
|
DataLayout* dtl = new DataLayout(F.getParent());
|
||||||
|
unsigned int ptr_size =
|
||||||
|
dtl->getPointerTypeSizeInBits(Type::getInt32PtrTy(F.getContext()));
|
||||||
|
|
||||||
|
for (auto i = F.begin(); i != F.end(); i++) {
|
||||||
|
BasicBlock* blk = &*i;
|
||||||
|
for (auto ii = blk->begin(); ii != blk->end(); ii++) {
|
||||||
|
Instruction* insn = &*ii;
|
||||||
|
if (insn->getOpcode() != Instruction::GetElementPtr) continue;
|
||||||
|
GetElementPtrInst* ele = (GetElementPtrInst*)insn;
|
||||||
|
Type* source = ele->getSourceElementType();
|
||||||
|
if (!source->isStructTy() ||
|
||||||
|
source->getStructName().str() != "struct.JNINativeInterface_")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
old_gets.push(insn);
|
||||||
|
insn = insn->getNextNonDebugInstruction();
|
||||||
|
|
||||||
|
// We are at the `getelementptr` instruction of the code
|
||||||
|
// Because `JNINativeInterface_` is a struct with only pointers
|
||||||
|
// we can consider it as an array of pointers
|
||||||
|
//
|
||||||
|
// It could be similar to the conversion from
|
||||||
|
// ```
|
||||||
|
// struct JNINativeInterface_ env;
|
||||||
|
// (*env)->doSomething(args);
|
||||||
|
// ````
|
||||||
|
// to
|
||||||
|
// ```
|
||||||
|
// struct JNINativeInterface_ env;
|
||||||
|
// typedef rettype (*doSomething)(args...);
|
||||||
|
// (doSomething)((int*)(*env)[doSomethingOffset])(args...);
|
||||||
|
// ```
|
||||||
|
// We first cast the `struct*` to an `int*`
|
||||||
|
// Calculate the new offset
|
||||||
|
// Add the base address to the offset to get the address to member
|
||||||
|
// Cast the address to a function pointer and call with the same
|
||||||
|
// arguments
|
||||||
|
//
|
||||||
|
// In LLVM, when `(*env)->doSomething` is accessed the LLVM IR
|
||||||
|
// generates a `getelementptr` instruction like this:
|
||||||
|
// ```
|
||||||
|
// getelementptr inbounds
|
||||||
|
// %struct.JNINativeInterface_,
|
||||||
|
// %struct.JNINativeInterface_* %R,
|
||||||
|
// i32 0,
|
||||||
|
// i32 memberIndex
|
||||||
|
// ````
|
||||||
|
// Where:
|
||||||
|
// %R is the pointer to the struct
|
||||||
|
// memberIndex is the index of the member in struct
|
||||||
|
// the third argument is 0 if %R is a pointer to the struct
|
||||||
|
// this is actually the same as how many dereference is needed
|
||||||
|
// *%R -> 0
|
||||||
|
// **%R -> 1
|
||||||
|
//
|
||||||
|
// We replace this instruction with
|
||||||
|
// ```
|
||||||
|
// %10 = bitcast %struct.JNINativeInterface_* %R to i64*
|
||||||
|
// %19 = getelementptr inbounds i64, i64* %10, i64 %OFFSET
|
||||||
|
// %20 = bitcast i64* %19 to FUNC_TYPE*
|
||||||
|
// %21 = load FUNC_TYPE, FUNC_TYPE* %20, align 8
|
||||||
|
//
|
||||||
|
// where FUNC_TYPE is
|
||||||
|
// i8* (%struct.JNINativeInterface_**, %struct._jobject*, i8*)*
|
||||||
|
// ```
|
||||||
|
// After that, we generate the equation to OFFSET (see below)
|
||||||
|
// which makes it harder to reverse
|
||||||
|
|
||||||
|
// generates a temp variable
|
||||||
|
Twine var_name = Twine(var_count);
|
||||||
|
AllocaInst* var =
|
||||||
|
new AllocaInst(Type::getInt32Ty(F.getContext()), 0, var_name, insn);
|
||||||
|
ConstantInt* y =
|
||||||
|
ConstantInt::getSigned(Type::getInt32Ty(F.getContext()),
|
||||||
|
llvm::cryptoutils->get_range(50, 100));
|
||||||
|
new StoreInst(y, var, insn);
|
||||||
|
|
||||||
|
Value* as_array = new BitCastInst(
|
||||||
|
ele->getPointerOperand(),
|
||||||
|
Type::getIntNPtrTy(F.getContext(), ptr_size), "", insn);
|
||||||
|
|
||||||
|
ConstantInt* index = (ConstantInt*)ele->getOperand(2);
|
||||||
|
BinaryOperator* new_index = nullptr;
|
||||||
|
if (index->isZero()) {
|
||||||
|
// generates the equation:
|
||||||
|
// a * y + b * y - c * y which is equal to 0
|
||||||
|
// where
|
||||||
|
// a + b = c
|
||||||
|
// y is a random number
|
||||||
|
//
|
||||||
|
// beware of bit size, we are using int32
|
||||||
|
// we have 31 bits to use, make sure not to overflow
|
||||||
|
//
|
||||||
|
// d is roughly 1000 to 2000
|
||||||
|
// a will have about 21 bits
|
||||||
|
// b = c - a = -(a - c)
|
||||||
|
|
||||||
|
int a_max = 1 << 21;
|
||||||
|
int a_min = 1 << 20;
|
||||||
|
// c is negative to mul easier
|
||||||
|
ConstantInt* c =
|
||||||
|
ConstantInt::getSigned(Type::getInt32Ty(F.getContext()),
|
||||||
|
llvm::cryptoutils->get_range(1000, 2000));
|
||||||
|
ConstantInt* a = ConstantInt::getSigned(
|
||||||
|
Type::getInt32Ty(F.getContext()),
|
||||||
|
llvm::cryptoutils->get_range(a_min, a_max));
|
||||||
|
// calculate b = -(a + (-c))
|
||||||
|
int b_value = -((int)a->getZExtValue() + (int)c->getZExtValue());
|
||||||
|
ConstantInt* b =
|
||||||
|
ConstantInt::getSigned(Type::getInt32Ty(F.getContext()), b_value);
|
||||||
|
|
||||||
|
// a * y + b * y
|
||||||
|
LoadInst* l1 = new LoadInst(Type::getInt32Ty(F.getContext()), var,
|
||||||
|
var_name, insn);
|
||||||
|
BinaryOperator* a_m =
|
||||||
|
BinaryOperator::CreateNSW(BinaryOperator::Mul, a, l1, "", insn);
|
||||||
|
LoadInst* l2 = new LoadInst(Type::getInt32Ty(F.getContext()), var,
|
||||||
|
var_name, insn);
|
||||||
|
BinaryOperator* b_m =
|
||||||
|
BinaryOperator::CreateNSW(BinaryOperator::Mul, b, l2, "", insn);
|
||||||
|
BinaryOperator* left = BinaryOperator::CreateNSW(BinaryOperator::Add,
|
||||||
|
a_m, b_m, "", insn);
|
||||||
|
// - c * y
|
||||||
|
LoadInst* l3 = new LoadInst(Type::getInt32Ty(F.getContext()), var,
|
||||||
|
var_name, insn);
|
||||||
|
BinaryOperator* right =
|
||||||
|
BinaryOperator::CreateNSW(BinaryOperator::Mul, c, l3, "", insn);
|
||||||
|
|
||||||
|
new_index = BinaryOperator::CreateNSW(BinaryOperator::Add, left,
|
||||||
|
right, "", insn);
|
||||||
|
} else {
|
||||||
|
// generates the equation:
|
||||||
|
// a * y + b * y + index * (1 - d * y) which is equal to index
|
||||||
|
// where
|
||||||
|
// index != 0
|
||||||
|
// a + b = d * index
|
||||||
|
// y is a random number
|
||||||
|
//
|
||||||
|
// beware of bit size, we are using int32
|
||||||
|
// we have 31 bits to use, make sure not to overflow
|
||||||
|
//
|
||||||
|
// d is roughly 1000 to 2000
|
||||||
|
// a will have about 21 bits
|
||||||
|
// b = (index * d - a) = -(a - index * d)
|
||||||
|
|
||||||
|
int a_max = 1 << 21;
|
||||||
|
int a_min = 1 << 20;
|
||||||
|
// d is negative to mul easier
|
||||||
|
ConstantInt* d =
|
||||||
|
ConstantInt::getSigned(Type::getInt32Ty(F.getContext()),
|
||||||
|
llvm::cryptoutils->get_range(1000, 2000));
|
||||||
|
ConstantInt* a = ConstantInt::getSigned(
|
||||||
|
Type::getInt32Ty(F.getContext()),
|
||||||
|
llvm::cryptoutils->get_range(a_min, a_max));
|
||||||
|
// calculate b = -(a + (index * -d)))))
|
||||||
|
int b_value = -((int)a->getZExtValue() +
|
||||||
|
(int)index->getZExtValue() * (int)d->getZExtValue());
|
||||||
|
ConstantInt* b =
|
||||||
|
ConstantInt::getSigned(Type::getInt32Ty(F.getContext()), b_value);
|
||||||
|
ConstantInt* one =
|
||||||
|
ConstantInt::getSigned(Type::getInt32Ty(F.getContext()), 1);
|
||||||
|
|
||||||
|
// a * y + b * y
|
||||||
|
LoadInst* l1 = new LoadInst(Type::getInt32Ty(F.getContext()), var,
|
||||||
|
var_name, insn);
|
||||||
|
BinaryOperator* a_m =
|
||||||
|
BinaryOperator::CreateNSW(BinaryOperator::Mul, a, l1, "", insn);
|
||||||
|
LoadInst* l2 = new LoadInst(Type::getInt32Ty(F.getContext()), var,
|
||||||
|
var_name, insn);
|
||||||
|
BinaryOperator* b_m =
|
||||||
|
BinaryOperator::CreateNSW(BinaryOperator::Mul, b, l2, "", insn);
|
||||||
|
BinaryOperator* left = BinaryOperator::CreateNSW(BinaryOperator::Add,
|
||||||
|
a_m, b_m, "", insn);
|
||||||
|
// index * (1 - d * y)
|
||||||
|
LoadInst* l3 = new LoadInst(Type::getInt32Ty(F.getContext()), var,
|
||||||
|
var_name, insn);
|
||||||
|
BinaryOperator* d_m =
|
||||||
|
BinaryOperator::CreateNSW(BinaryOperator::Mul, d, l3, "", insn);
|
||||||
|
BinaryOperator* add_one = BinaryOperator::CreateNSW(
|
||||||
|
BinaryOperator::Add, d_m, one, "", insn);
|
||||||
|
BinaryOperator* right = BinaryOperator::CreateNSW(
|
||||||
|
BinaryOperator::Mul, index, add_one, "", insn);
|
||||||
|
|
||||||
|
new_index = BinaryOperator::CreateNSW(BinaryOperator::Add, left,
|
||||||
|
right, "", insn);
|
||||||
|
}
|
||||||
|
GetElementPtrInst* new_get =
|
||||||
|
GetElementPtrInst::CreateInBounds(as_array, {
|
||||||
|
// getelementptr reuires the index to be int64
|
||||||
|
new SExtInst(new_index, Type::getInt64Ty(F.getContext()), "",
|
||||||
|
insn);
|
||||||
|
}, "", insn);
|
||||||
|
|
||||||
|
// store
|
||||||
|
if (StoreInst::classof(insn)) {
|
||||||
|
// may not need, no one set on JNIEnv
|
||||||
|
insn->setOperand(1, new_get);
|
||||||
|
}
|
||||||
|
// load
|
||||||
|
else if (LoadInst::classof(insn)) {
|
||||||
|
// cast the int* to function pointer
|
||||||
|
// the type of the function pointer is load type
|
||||||
|
Value* func_ptr = new BitCastInst(
|
||||||
|
new_get, ((LoadInst*)insn)->getPointerOperandType(), "", insn);
|
||||||
|
insn->setOperand(0, func_ptr);
|
||||||
|
} else {
|
||||||
|
errs() << "Unknown instruction after getptr:\n\t" << *insn << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// erase old gets
|
||||||
|
while (!old_gets.empty()) {
|
||||||
|
old_gets.top()->eraseFromParent();
|
||||||
|
old_gets.pop();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
char StructOffsetJni::ID = 1;
|
||||||
|
static RegisterPass<StructOffsetJni> JNI("jnienv",
|
||||||
|
"Randomly offset JNIEnv's members");
|
||||||
|
|
70
creator/internal-efiensctf-2020/flag.js
Normal file
70
creator/internal-efiensctf-2020/flag.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const { check_password } = internalBinding('flag');
|
||||||
|
|
||||||
|
function easy(input_flag) {
|
||||||
|
let flag_components = input_flag.split('-');
|
||||||
|
let message = '';
|
||||||
|
let x = 0x9bc19a11;
|
||||||
|
while (x !== 0xdeadbeef) {
|
||||||
|
switch(x) {
|
||||||
|
case 0x54f5d109: {
|
||||||
|
message = 'You are dead wrong';
|
||||||
|
x = 0xdeadbeef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x22f1dede: {
|
||||||
|
message = 'The flag is efiensctf{' + input_flag + '}';
|
||||||
|
x = 0xdeadbeef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x9bc19a11: {
|
||||||
|
x = flag_components.length === 4
|
||||||
|
? 0xab9a16fd
|
||||||
|
: 0x54f5d109;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x589f0521: {
|
||||||
|
x = flag_components[0] === 'do'
|
||||||
|
? 0x27c501f3
|
||||||
|
: 0x54f5d109;
|
||||||
|
flag_components.shift();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0e2c6464: {
|
||||||
|
x = flag_components[0] === 'know'
|
||||||
|
? 0x22f1dede
|
||||||
|
: 0x54f5d109;
|
||||||
|
flag_components.shift();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x27c501f3: {
|
||||||
|
x = flag_components[0] === 'you'
|
||||||
|
? 0x0e2c6464
|
||||||
|
: 0x54f5d109;
|
||||||
|
flag_components.shift();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xab9a16fd: {
|
||||||
|
x = flag_components[0] === 'nodejs'
|
||||||
|
? 0x589f0521
|
||||||
|
: 0x54f5d109;
|
||||||
|
flag_components.shift();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
function medium(pass) {
|
||||||
|
if (check_password(pass)) {
|
||||||
|
console.log("Submit the password as flag");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("What did you miss?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = flag = {
|
||||||
|
easy,
|
||||||
|
medium,
|
||||||
|
};
|
BIN
creator/internal-efiensctf-2020/node
Normal file
BIN
creator/internal-efiensctf-2020/node
Normal file
Binary file not shown.
137
creator/internal-efiensctf-2020/node_flag.cc
Normal file
137
creator/internal-efiensctf-2020/node_flag.cc
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// Copyright luibo. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "node.h"
|
||||||
|
#include "env-inl.h"
|
||||||
|
#include "util-inl.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) || defined(_MSC_VER)
|
||||||
|
# include <io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace node {
|
||||||
|
|
||||||
|
namespace flag {
|
||||||
|
|
||||||
|
using v8::Array;
|
||||||
|
using v8::Context;
|
||||||
|
using v8::EscapableHandleScope;
|
||||||
|
using v8::Function;
|
||||||
|
using v8::FunctionCallbackInfo;
|
||||||
|
using v8::FunctionTemplate;
|
||||||
|
using v8::HandleScope;
|
||||||
|
using v8::Int32;
|
||||||
|
using v8::Integer;
|
||||||
|
using v8::Isolate;
|
||||||
|
using v8::Local;
|
||||||
|
using v8::MaybeLocal;
|
||||||
|
using v8::Number;
|
||||||
|
using v8::Object;
|
||||||
|
using v8::ObjectTemplate;
|
||||||
|
using v8::Promise;
|
||||||
|
using v8::String;
|
||||||
|
using v8::Symbol;
|
||||||
|
using v8::Uint32;
|
||||||
|
using v8::Undefined;
|
||||||
|
using v8::Value;
|
||||||
|
|
||||||
|
char encrypted[42] = {
|
||||||
|
0x0b, 0x09, 0x0d, 0x00, 0x00, 0x1c, 0x07,
|
||||||
|
0x11, 0x08, 0x14, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||||
|
0x0e, 0x16, 0x43, 0x06, 0x17, 0x48, 0x03,
|
||||||
|
0x0e, 0x0d, 0x0b, 0x02, 0x16, 0x49, 0x12,
|
||||||
|
0x1c, 0x06, 0x10, 0x11, 0x0b, 0x01, 0x49,
|
||||||
|
0x0c, 0x00, 0x42, 0x27, 0x35, 0x3e, 0x12
|
||||||
|
};
|
||||||
|
|
||||||
|
char key[4] = {0x6e, 0x6f, 0x64, 0x65};
|
||||||
|
|
||||||
|
void CheckPassword(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
Isolate* isolate = env->isolate();
|
||||||
|
|
||||||
|
if (args.Length() != 1) {
|
||||||
|
std::cout << "give me one and only one argument" << std::endl;
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!args[0]->IsString()) {
|
||||||
|
std::cout << "we only accept string" << std::endl;
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String* password = String::Cast(*args[0]);
|
||||||
|
if (!password->ContainsOnlyOneByte()) {
|
||||||
|
std::cout << "provide a utf8 string pleaze" << std::endl;
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int length = password->Utf8Length(isolate);
|
||||||
|
if (length != 7 * 6) {
|
||||||
|
std::cout << "password length is not correct" << std::endl;
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(sizeof(char) * length);
|
||||||
|
password->WriteUtf8(isolate, buffer, length);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
// std::cout << (char)(encrypted[i] ^ key[i % 4]) << std::endl;
|
||||||
|
if (buffer[i] != (encrypted[i] ^ key[i % 4])) {
|
||||||
|
free(buffer);
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
args.GetReturnValue().Set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(Local<Object> target,
|
||||||
|
Local<Value> unused,
|
||||||
|
Local<Context> context,
|
||||||
|
void* priv) {
|
||||||
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
// Isolate* isolate = env->isolate();
|
||||||
|
|
||||||
|
env->SetMethod(target, "check_password", CheckPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flag
|
||||||
|
|
||||||
|
} // end namespace node
|
||||||
|
|
||||||
|
NODE_MODULE_CONTEXT_AWARE_INTERNAL(flag, node::flag::Initialize)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user