void EventSystem::handleKeyPress(SDL_keysym *keysym, bool down) { std::string evtype(down ? "keydown_" : "keyup_"); switch (keysym->sym) { #include "keys.hpp" default: break; } Event ev(evtype.c_str()); events.push(ev); }
void cli_event_debug(cli_events_t *ctx, unsigned id) { const char *tstr; struct cli_event *ev = get_event(ctx, id); if (!ev) return; tstr = evtype(ev->type); if (ev->multiple == multiple_chain && ev->type != ev_data) { unsigned i; cli_dbgmsg("%s: ev_chain %u %s\n", ev->name, ev->count, tstr); for (i=0;i<ev->count;i++) ev_debug(ev->type, &ev->u.v_chain[i], i); } else { cli_dbgmsg("%s: %s\n", ev->name, tstr); ev_debug(ev->type, &ev->u, ev->count); } }
void rename_classes( Scope& scope, std::vector<std::string>& pre_whitelist_patterns, std::vector<std::string>& post_whitelist_patterns, const std::string& path, std::unordered_set<const DexType*>& untouchables, ProguardMap& proguard_map, bool rename_annotations) { unpackage_private(scope); int clazz_ident = 0; std::map<DexString*, DexString*> aliases; for(auto clazz: scope) { if (!should_rename( clazz, pre_whitelist_patterns, post_whitelist_patterns, untouchables, rename_annotations)) { continue; } char clzname[4]; get_next_ident(clzname, clazz_ident); auto dtype = clazz->get_type(); auto oldname = dtype->get_name(); // The X helps our hacked Dalvik classloader recognize that a // class name is the output of the redex renamer and thus will // never be found in the Android platform. // The $ indicates that the class was originally an inner class. // Some code, most notably android instrumentation runner, uses // this information to decide whether or not to classload the class. bool inner = strrchr(oldname->c_str(), '$'); char descriptor[10]; sprintf(descriptor, "LX%s%s;", inner ? "$" : "", clzname); auto dstring = DexString::make_string(descriptor); aliases[oldname] = dstring; dtype->assign_name_alias(dstring); std::string old_str(oldname->c_str()); std::string new_str(descriptor); proguard_map.update_class_mapping(old_str, new_str); base_strings_size += strlen(oldname->c_str()); base_strings_size += strlen(dstring->c_str()); TRACE(RENAME, 4, "'%s'->'%s'\n", oldname->c_str(), descriptor); while (1) { std::string arrayop("["); arrayop += oldname->c_str(); oldname = DexString::get_string(arrayop.c_str()); if (oldname == nullptr) { break; } auto arraytype = DexType::get_type(oldname); if (arraytype == nullptr) { break; } std::string newarraytype("["); newarraytype += dstring->c_str(); dstring = DexString::make_string(newarraytype.c_str()); aliases[oldname] = dstring; arraytype->assign_name_alias(dstring); } } /* Now we need to re-write the Signature annotations. They use * Strings rather than Type's, so they have to be explicitly * handled. */ /* Generics of the form Type<> turn into the Type string * sans the ';'. So, we have to alias those if they * exist. Signature annotations suck. */ for (auto apair : aliases) { char buf[MAX_DESCRIPTOR_LENGTH]; const char *sourcestr = apair.first->c_str(); size_t sourcelen = strlen(sourcestr); if (sourcestr[sourcelen - 1] != ';') continue; strcpy(buf, sourcestr); buf[sourcelen - 1] = '\0'; auto dstring = DexString::get_string(buf); if (dstring == nullptr) continue; strcpy(buf, apair.second->c_str()); buf[strlen(apair.second->c_str()) - 1] = '\0'; auto target = DexString::make_string(buf); aliases[dstring] = target; } walk_annotations(scope, [&](DexAnnotation* anno) { static DexType *dalviksig = DexType::get_type("Ldalvik/annotation/Signature;"); if (anno->type() != dalviksig) return; auto elems = anno->anno_elems(); for (auto elem : elems) { auto ev = elem.encoded_value; if (ev->evtype() != DEVT_ARRAY) continue; auto arrayev = static_cast<DexEncodedValueArray*>(ev); auto const& evs = arrayev->evalues(); for (auto strev : *evs) { if (strev->evtype() != DEVT_STRING) continue; auto stringev = static_cast<DexEncodedValueString*>(strev); if (aliases.count(stringev->string())) { TRACE(RENAME, 5, "Rewriting Signature from '%s' to '%s'\n", stringev->string()->c_str(), aliases[stringev->string()]->c_str()); stringev->string(aliases[stringev->string()]); } } } }); if (!path.empty()) { FILE* fd = fopen(path.c_str(), "w"); if (fd == nullptr) { perror("Error writing rename file"); return; } for (const auto &it : aliases) { // record for later processing and back map generation fprintf(fd, "%s -> %s\n",it.first->c_str(), it.second->c_str()); } fclose(fd); } for (auto clazz : scope) { clazz->get_vmethods().sort(compare_dexmethods); clazz->get_dmethods().sort(compare_dexmethods); clazz->get_sfields().sort(compare_dexfields); clazz->get_ifields().sort(compare_dexfields); } }
/** * Walks all the code of the app, finding classes that are reachable from * code. * * Note that as code is changed or removed by Redex, this information will * become stale, so this method should be called periodically, for example * after each pass. */ void recompute_classes_reachable_from_code(const Scope& scope) { for (auto clazz : scope) { clazz->rstate.clear_if_compute(); } std::unordered_set<DexString*> maybetypes; walk_annotations(scope, [&](DexAnnotation* anno) { static DexType* dalviksig = DexType::get_type("Ldalvik/annotation/Signature;"); // Signature annotations contain strings that Jackson uses // to construct the underlying types. We capture the // full list here, and mark them later. (There are many // duplicates, so de-duping before we look it up as a class // makes sense) if (anno->type() == dalviksig) { auto elems = anno->anno_elems(); for (auto const& elem : elems) { auto ev = elem.encoded_value; if (ev->evtype() != DEVT_ARRAY) continue; auto arrayev = static_cast<DexEncodedValueArray*>(ev); auto const& evs = arrayev->evalues(); for (auto strev : *evs) { if (strev->evtype() != DEVT_STRING) continue; auto stringev = static_cast<DexEncodedValueString*>(strev); maybetypes.insert((DexString*)stringev->string()); } } return; } // Class literals in annotations. // // Example: // @JsonDeserialize(using=MyJsonDeserializer.class) // ^^^^ if (anno->runtime_visible()) { auto elems = anno->anno_elems(); for (auto const& dae : elems) { auto evalue = dae.encoded_value; std::vector<DexType*> ltype; evalue->gather_types(ltype); if (ltype.size()) { for (auto dextype : ltype) { mark_reachable_directly(dextype); } } } } }); // Now we process the strings that were in the signature // annotations. // Note: We do not mark these as ref'd by string, because // these cases are handleable for renaming. for (auto dstring : maybetypes) { const char* cstr = dstring->c_str(); int len = strlen(cstr); if (len < 3) continue; if (cstr[0] != 'L') continue; if (cstr[len - 1] == ';') { auto dtype = DexType::get_type(dstring); mark_reachable_directly(dtype); continue; } std::string buf(cstr); buf += ';'; auto dtype = DexType::get_type(buf.c_str()); mark_reachable_directly(dtype); } // Matches methods marked as native walk_methods(scope, [&](DexMethod* meth) { if (meth->get_access() & DexAccessFlags::ACC_NATIVE) { mark_reachable_by_classname(meth->get_class(), true); } }); walk_code(scope, [](DexMethod*) { return true; }, [&](DexMethod* meth, DexCode* code) { auto opcodes = code->get_instructions(); for (const auto& opcode : opcodes) { // Matches any stringref that name-aliases a type. if (opcode->has_strings()) { auto stringop = static_cast<DexOpcodeString*>(opcode); DexString* dsclzref = stringop->get_string(); DexType* dtexclude = get_dextype_from_dotname(dsclzref->c_str()); if (dtexclude == nullptr) continue; mark_reachable_by_classname(dtexclude, true); } if (opcode->has_types()) { // Matches the following instructions (from most to least // common): // check-cast, new-instance, const-class, instance-of // new-instance should not be on this list, and // we should not allow these to operate on themselves. // TODO(snay/dalves) auto typeop = static_cast<DexOpcodeType*>(opcode); mark_reachable_directly(typeop->get_type()); } } }); }