├── .gitignore ├── MappingParser.py ├── README.md ├── Translator.py ├── beautify.png ├── debug.py ├── main.py ├── obfucate.png ├── pojo.py ├── template.dat └── template.mapping /.gitignore: -------------------------------------------------------------------------------- 1 | mapping.txt 2 | *.pyc 3 | -------------------------------------------------------------------------------- /MappingParser.py: -------------------------------------------------------------------------------- 1 | 2 | import os, re 3 | 4 | from debug import * 5 | from pojo import * 6 | 7 | class Parser: 8 | def __init__(self, mappingFile): 9 | self.finalDict = parse(mappingFile) 10 | self.machine = re.compile('(.*)\.([^\.]+)(\(.*\))') 11 | 12 | def translate(self, fullCode): 13 | # fullCode such as android.support.design.widget.TabLayout.g(xxyy) 14 | if DEBUG: 15 | print('translate "%s"' % fullCode) 16 | 17 | m = self.machine.match(fullCode) 18 | if not m: 19 | return fullCode 20 | 21 | className = m.group(1) 22 | functionName = m.group(2) 23 | others = m.group(3) 24 | if className not in self.finalDict: 25 | return fullCode 26 | classC = self.finalDict[className] 27 | actualClassName = classC.name 28 | actualFunctionName = functionName 29 | actualFunction = classC.get(functionName, isFunction=True) 30 | if actualFunction: 31 | actualFunctionName = actualFunction.name 32 | 33 | if others: 34 | return "%s.%s%s" % (actualClassName, actualFunctionName, others) 35 | else: 36 | return "%s.%s" % (actualClassName, actualFunctionName) 37 | 38 | 39 | def parse(mappingFile): 40 | assert os.path.exists(mappingFile), "mappingFile %s is not exists" % mappingFile 41 | 42 | print('parsing') 43 | 44 | finalResult = {} # mappingName -> Class 45 | 46 | classParser = ClassParser() 47 | memberParser = MemberParser() 48 | functionParser = FunctionParser() 49 | 50 | currentClass = None 51 | with open(mappingFile, 'r') as f: 52 | for line in f: 53 | c = classParser.match(line) 54 | if c: 55 | if currentClass: 56 | finalResult[currentClass.mappingName] = currentClass 57 | if DEBUG: 58 | print('match a class %s' % c) 59 | currentClass = c 60 | continue 61 | f = functionParser.match(line) 62 | if f: 63 | assert currentClass, "mapping file should start with a class" 64 | currentClass.add(f) 65 | if DEBUG: 66 | print('match a function %s' % f) 67 | continue 68 | m = memberParser.match(line) 69 | if m: 70 | assert currentClass, "mapping file should start with a class" 71 | currentClass.add(m) 72 | if DEBUG: 73 | print('match a member %s' % m) 74 | continue 75 | 76 | if currentClass: 77 | finalResult[currentClass.mappingName] = currentClass 78 | 79 | # print it 80 | if DEBUG: 81 | print(finalResult) 82 | print('parse end') 83 | return finalResult 84 | 85 | class ClassParser: 86 | def __init__(self): 87 | self.machine = re.compile('^([^ ]+) -> ([^:]+):') 88 | 89 | def match(self, line): 90 | m = self.machine.match(line) 91 | if not m: 92 | return None 93 | name = m.group(1) 94 | mappingName = m.group(2) 95 | return Class(name, mappingName) 96 | 97 | class MemberParser: 98 | def __init__(self): 99 | self.machine = re.compile('^ {4}([^ ]+) ([^ ]+) -> (.*)') 100 | 101 | def match(self, line): 102 | m = self.machine.match(line) 103 | if not m: 104 | return None 105 | type = m.group(1) 106 | name = m.group(2) 107 | mappingName = m.group(3) 108 | return MemberVar(type, name, mappingName) 109 | 110 | class FunctionParser: 111 | def __init__(self): 112 | self.machine = re.compile('^ {4}(([0-9]+):)?(([0-9]+):)?([^ ]+) ([^ ]+)\((.*)\) -> (.*)') 113 | 114 | def match(self, line): 115 | m = self.machine.match(line) 116 | if not m: 117 | return None 118 | oldLocation = m.group(2) 119 | newLocation = m.group(4) 120 | type = m.group(5) 121 | name = m.group(6) 122 | arguments = m.group(7) 123 | mappingName = m.group(8) 124 | return Function(type, name, arguments, mappingName, oldLocation, newLocation) 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Mapping Translator 3 | 4 | We often feel confused when facing the the obfuscated code like this: 5 | ![Obfuscated code](obfucate.png) 6 | 7 | It's time to make a change! 8 | 9 | Use this, and the world will be beautified. 10 | ![beauty](beautify.png) 11 | 12 | Let's begin with [main.py](main.py) 13 | 14 | -------------------------------------------------------------------------------- /Translator.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | 4 | import MappingParser 5 | 6 | class Translator: 7 | def __init__(self, mappingFile): 8 | self.parser = MappingParser.Parser(mappingFile) 9 | self.fullCodeRetriver = re.compile(r'\b[^\( ]+\([^\)]+\)') 10 | 11 | def translate(self, fullContent): 12 | result = "" 13 | start = 0 14 | m = self.fullCodeRetriver.search(fullContent, start) 15 | while m: 16 | 17 | # letters before 18 | letterStart = m.start() 19 | result += fullContent[start:letterStart] 20 | 21 | # letters 22 | letters = m.group(0) 23 | translations = self.parser.translate(letters) 24 | result += translations 25 | 26 | # letters after 27 | # pass 28 | 29 | start = m.end() 30 | m = self.fullCodeRetriver.search(fullContent, start) 31 | 32 | # the rest 33 | result += fullContent[start:] 34 | 35 | return result 36 | -------------------------------------------------------------------------------- /beautify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leteno/mapping-parser/9b58488c138e13d3d0122c9d283fedb349f76a6b/beautify.png -------------------------------------------------------------------------------- /debug.py: -------------------------------------------------------------------------------- 1 | 2 | DEBUG = None 3 | # DEBUG = "YES" 4 | 5 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | from Translator import * 5 | 6 | def test(): 7 | translator = Translator('template.mapping') 8 | filename = 'template.dat' 9 | f = open(filename, 'r') 10 | assert f, "error when open %s" % filename 11 | content = f.read() 12 | print('before: \n%s\n' % content) 13 | translation = translator.translate(content) 14 | print('after: \n%s\n' % translation) 15 | 16 | test() 17 | -------------------------------------------------------------------------------- /obfucate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leteno/mapping-parser/9b58488c138e13d3d0122c9d283fedb349f76a6b/obfucate.png -------------------------------------------------------------------------------- /pojo.py: -------------------------------------------------------------------------------- 1 | 2 | class Class: 3 | def __init__(self, name, mappingName): 4 | self.name = name 5 | self.mappingName = mappingName 6 | self.children = [] 7 | 8 | def add(self, child): 9 | self.children.append(child) 10 | 11 | def get(self, childMappingName, isFunction=True): 12 | for c in self.children: 13 | if isFunction and not isinstance(c, Function): 14 | continue 15 | if not isFunction and not isinstance(c, MemberVar): 16 | continue 17 | if c.mappingName == childMappingName: 18 | return c 19 | 20 | def __str__(self): 21 | childrenWords = "" 22 | for child in self.children: 23 | childrenWords += "%s," % child 24 | return "{name: %s, mappingName: %s, [%s]}" % (self.name, self.mappingName, childrenWords) 25 | 26 | class MemberVar: 27 | def __init__(self, type, name, mappingName, oldLocation=None, newLocation=None): 28 | self.type = type 29 | self.name = name 30 | self.mappingName = mappingName 31 | self.oldLocation = oldLocation 32 | self.newLocation = newLocation 33 | 34 | def __str__(self): 35 | return "{type: %s, name: %s, mappingName: %s}" % (self.type, self.name, self.mappingName) 36 | 37 | class Function: 38 | def __init__(self, type, name, arguments, mappingName, oldLocation=None, newLocation=None): 39 | self.type = type 40 | self.name = name 41 | self.arguments = arguments 42 | self.mappingName = mappingName 43 | self.oldLocation = oldLocation 44 | self.newLocation = newLocation 45 | 46 | def __str__(self): 47 | return "{type: %s, name: %s, args: %s, mappingName: %s, oldLoc: %s, newLoc: %s}" % \ 48 | (self.type, self.name, self.arguments, self.mappingName, self.oldLocation, self.newLocation) 49 | -------------------------------------------------------------------------------- /template.dat: -------------------------------------------------------------------------------- 1 | FATAL EXCEPTION: main 2 | Process: com.zhihu.android, PID: 24534 3 | java.lang.NullPointerException: Attempt to invoke virtual method 'android.support.v4.app.Fragment com.zhihu.android.app.market.fragment.markethome.b.a(int)' on a null object reference 4 | at com.zhihu.android.app.market.fragment.MarketFragment2.c(MarketFragment2.java:634) 5 | at com.zhihu.android.app.ui.activity.MainActivity.c(MainActivity.java:1171) 6 | at android.support.design.widget.TabLayout.g(TabLayout.java:1177) 7 | at android.support.design.widget.TabLayout.b(TabLayout.java:1136) 8 | at android.support.design.widget.TabLayout.b(TabLayout.java:1128) 9 | at android.support.design.widget.TabLayout$e.f(TabLayout.java:1427) 10 | at android.support.design.widget.TabLayout$g.performClick(TabLayout.java:1537) 11 | at android.view.View$PerformClick.run(View.java:24931) 12 | at android.os.Handler.handleCallback(Handler.java:808) 13 | at android.os.Handler.dispatchMessage(Handler.java:101) 14 | at android.os.Looper.loop(Looper.java:166) 15 | at android.app.ActivityThread.main(ActivityThread.java:7425) 16 | at java.lang.reflect.Method.invoke(Native Method) 17 | at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245) 18 | at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921) 19 | -------------------------------------------------------------------------------- /template.mapping: -------------------------------------------------------------------------------- 1 | com.zhihu.android.app.market.fragment.markethome.MarketHomeAdapter -> com.zhihu.android.app.market.fragment.markethome.b: 2 | java.util.List mTags -> a 3 | java.util.List mFragments -> b 4 | 33:46:void (android.support.v4.app.FragmentManager,java.util.List) -> 5 | 50:50:android.support.v4.app.Fragment getItem(int) -> a 6 | 55:55:int getCount() -> b 7 | 60:60:java.lang.CharSequence getPageTitle(int) -> c 8 | com.zhihu.android.app.market.fragment.MarketFragment2 -> com.zhihu.android.app.market.fragment.MarketFragment2: 9 | 632:638:void onTabReselected(android.support.design.widget.TabLayout$Tab) -> c 10 | 129:129:void () -> 11 | android.support.design.widget.TabLayout -> android.support.design.widget.TabLayout: 12 | android.support.v4.util.Pools$Pool sTabPool -> n 13 | java.util.ArrayList mTabs -> o 14 | android.support.design.widget.TabLayout$Tab mSelectedTab -> p 15 | android.support.design.widget.TabLayout$SlidingTabStrip mTabStrip -> q 16 | int mTabPaddingStart -> a 17 | int mTabPaddingTop -> b 18 | int mTabPaddingEnd -> c 19 | int mTabPaddingBottom -> d 20 | int mTabTextAppearance -> e 21 | android.content.res.ColorStateList mTabTextColors -> f 22 | float mTabTextSize -> g 23 | float mTabTextMultiLineSize -> h 24 | int mTabBackgroundResId -> i 25 | int mTabMaxWidth -> j 26 | int mRequestedTabMinWidth -> r 27 | int mRequestedTabMaxWidth -> s 28 | int mScrollableTabMinWidth -> t 29 | int mContentInsetStart -> u 30 | int mTabGravity -> k 31 | int mMode -> l 32 | android.support.design.widget.TabLayout$OnTabSelectedListener mSelectedListener -> v 33 | java.util.ArrayList mSelectedListeners -> w 34 | android.support.design.widget.TabLayout$OnTabSelectedListener mCurrentVpSelectedListener -> x 35 | android.animation.ValueAnimator mScrollAnimator -> y 36 | android.support.v4.view.ViewPager mViewPager -> m 37 | android.support.v4.view.PagerAdapter mPagerAdapter -> z 38 | android.database.DataSetObserver mPagerAdapterObserver -> A 39 | android.support.design.widget.TabLayout$TabLayoutOnPageChangeListener mPageChangeListener -> B 40 | android.support.design.widget.TabLayout$AdapterChangeListener mAdapterChangeListener -> C 41 | boolean mSetupViewPagerImplicitly -> D 42 | android.support.v4.util.Pools$Pool mTabViewPool -> E 43 | 288:289:void (android.content.Context) -> 44 | 292:293:void (android.content.Context,android.util.AttributeSet) -> 45 | 244:371:void (android.content.Context,android.util.AttributeSet,int) -> 46 | 381:382:void setSelectedTabIndicatorColor(int) -> setSelectedTabIndicatorColor 47 | 392:393:void setSelectedTabIndicatorHeight(int) -> setSelectedTabIndicatorHeight 48 | 406:407:void setScrollPosition(int,float,boolean) -> a 49 | 411:431:void setScrollPosition(int,float,boolean,boolean) -> a 50 | 434:434:float getScrollPosition() -> getScrollPosition 51 | 444:445:void addTab(android.support.design.widget.TabLayout$Tab) -> a 52 | 465:466:void addTab(android.support.design.widget.TabLayout$Tab,boolean) -> a 53 | 476:485:void addTab(android.support.design.widget.TabLayout$Tab,int,boolean) -> a 54 | 488:502:void addTabFromItemView(android.support.design.widget.TabItem) -> a 55 | 512:521:void setOnTabSelectedListener(android.support.design.widget.TabLayout$OnTabSelectedListener) -> setOnTabSelectedListener 56 | 533:536:void addOnTabSelectedListener(android.support.design.widget.TabLayout$OnTabSelectedListener) -> a 57 | 545:546:void removeOnTabSelectedListener(android.support.design.widget.TabLayout$OnTabSelectedListener) -> b 58 | 564:570:android.support.design.widget.TabLayout$Tab newTab() -> a 59 | 579:579:int getTabCount() -> getTabCount 60 | 587:587:android.support.design.widget.TabLayout$Tab getTabAt(int) -> a 61 | 596:596:int getSelectedTabPosition() -> getSelectedTabPosition 62 | 644:656:void removeAllTabs() -> b 63 | 674:678:void setTabMode(int) -> setTabMode 64 | 687:687:int getTabMode() -> getTabMode 65 | 698:702:void setTabGravity(int) -> setTabGravity 66 | 711:711:int getTabGravity() -> getTabGravity 67 | 720:724:void setTabTextColors(android.content.res.ColorStateList) -> setTabTextColors 68 | 731:731:android.content.res.ColorStateList getTabTextColors() -> getTabTextColors 69 | 741:742:void setTabTextColors(int,int) -> a 70 | 753:754:void setupWithViewPager(android.support.v4.view.ViewPager) -> setupWithViewPager 71 | 775:776:void setupWithViewPager(android.support.v4.view.ViewPager,boolean) -> a 72 | 780:834:void setupWithViewPager(android.support.v4.view.ViewPager,boolean,boolean) -> a 73 | 843:844:void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter) -> setTabsFromPagerAdapter 74 | 849:849:boolean shouldDelayChildPressedState() -> shouldDelayChildPressedState 75 | 854:866:void onAttachedToWindow() -> onAttachedToWindow 76 | 870:877:void onDetachedFromWindow() -> onDetachedFromWindow 77 | 880:881:int getTabScrollRange() -> getTabScrollRange 78 | 885:902:void setPagerAdapter(android.support.v4.view.PagerAdapter,boolean) -> a 79 | 905:921:void populateFromPagerAdapter() -> c 80 | 924:927:void updateAllTabs() -> d 81 | 930:937:android.support.design.widget.TabLayout$TabView createTabView(android.support.design.widget.TabLayout$Tab) -> c 82 | 941:948:void configureTab(android.support.design.widget.TabLayout$Tab,int) -> a 83 | 951:953:void addTabView(android.support.design.widget.TabLayout$Tab) -> d 84 | 957:958:void addView(android.view.View) -> addView 85 | 962:963:void addView(android.view.View,int) -> addView 86 | 967:968:void addView(android.view.View,android.view.ViewGroup$LayoutParams) -> addView 87 | 972:973:void addView(android.view.View,int,android.view.ViewGroup$LayoutParams) -> addView 88 | 976:981:void addViewInternal(android.view.View) -> a 89 | 984:987:android.widget.LinearLayout$LayoutParams createLayoutParamsForTabs() -> e 90 | 991:998:void updateTabViewLayoutParams(android.widget.LinearLayout$LayoutParams) -> a 91 | 1001:1001:int dpToPx(int) -> b 92 | 1008:1059:void onMeasure(int,int) -> onMeasure 93 | 1062:1069:void removeTabViewAt(int) -> c 94 | 1072:1096:void animateToTab(int) -> d 95 | 1099:1110:void ensureScrollAnimator() -> f 96 | 1113:1115:void setScrollAnimatorListener(android.animation.Animator$AnimatorListener) -> setScrollAnimatorListener 97 | 1118:1125:void setSelectedTabView(int) -> setSelectedTabView 98 | 1128:1129:void selectTab(android.support.design.widget.TabLayout$Tab) -> b 99 | 1132:1161:void selectTab(android.support.design.widget.TabLayout$Tab,boolean) -> b 100 | 1164:1167:void dispatchTabSelected(android.support.design.widget.TabLayout$Tab) -> e 101 | 1170:1173:void dispatchTabUnselected(android.support.design.widget.TabLayout$Tab) -> f 102 | 1176:1179:void dispatchTabReselected(android.support.design.widget.TabLayout$Tab) -> g 103 | 1182:1199:int calculateScrollXForTab(int,float) -> a 104 | 1203:1220:void applyModeAndGravity() -> g 105 | 1223:1231:void updateTabViews(boolean) -> a 106 | 2045:2058:android.content.res.ColorStateList createColorStateList(int,int) -> b 107 | 2062:2070:int getDefaultHeight() -> getDefaultHeight 108 | 2074:2079:int getTabMinWidth() -> getTabMinWidth 109 | 2088:2088:android.widget.FrameLayout$LayoutParams generateLayoutParams(android.util.AttributeSet) -> generateLayoutParams 110 | 2092:2092:int getTabMaxWidth() -> getTabMaxWidth 111 | 148:148:android.view.ViewGroup$LayoutParams generateLayoutParams(android.util.AttributeSet) -> generateLayoutParams 112 | 161:161:void () -> 113 | android.support.design.widget.TabLayout$Tab -> android.support.design.widget.TabLayout$e: 114 | java.lang.Object mTag -> c 115 | android.graphics.drawable.Drawable mIcon -> d 116 | java.lang.CharSequence mText -> e 117 | java.lang.CharSequence mContentDesc -> f 118 | int mPosition -> g 119 | android.view.View mCustomView -> h 120 | android.support.design.widget.TabLayout mParent -> a 121 | android.support.design.widget.TabLayout$TabView mView -> b 122 | 1249:1257:void () -> 123 | 1264:1264:java.lang.Object getTag() -> a 124 | 1275:1276:android.support.design.widget.TabLayout$Tab setTag(java.lang.Object) -> a 125 | 1288:1288:android.view.View getCustomView() -> b 126 | 1306:1308:android.support.design.widget.TabLayout$Tab setCustomView(android.view.View) -> a 127 | 1326:1327:android.support.design.widget.TabLayout$Tab setCustomView(int) -> a 128 | 1337:1337:android.graphics.drawable.Drawable getIcon() -> c 129 | 1347:1347:int getPosition() -> d 130 | 1351:1352:void setPosition(int) -> b 131 | 1361:1361:java.lang.CharSequence getText() -> e 132 | 1372:1374:android.support.design.widget.TabLayout$Tab setIcon(android.graphics.drawable.Drawable) -> a 133 | 1385:1388:android.support.design.widget.TabLayout$Tab setIcon(int) -> c 134 | 1400:1402:android.support.design.widget.TabLayout$Tab setText(java.lang.CharSequence) -> a 135 | 1424:1428:void select() -> f 136 | 1434:1437:boolean isSelected() -> g 137 | 1468:1470:android.support.design.widget.TabLayout$Tab setContentDescription(java.lang.CharSequence) -> b 138 | 1482:1482:java.lang.CharSequence getContentDescription() -> h 139 | 1486:1489:void updateView() -> i 140 | 1492:1500:void reset() -> j 141 | android.support.design.widget.TabLayout$TabView -> android.support.design.widget.TabLayout$g: 142 | android.support.design.widget.TabLayout$Tab mTab -> b 143 | android.widget.TextView mTextView -> c 144 | android.widget.ImageView mIconView -> d 145 | android.view.View mCustomView -> e 146 | android.widget.TextView mCustomTextView -> f 147 | android.widget.ImageView mCustomIconView -> g 148 | int mDefaultMaxLines -> h 149 | android.support.design.widget.TabLayout this$0 -> a 150 | 1512:1527:void (android.support.design.widget.TabLayout,android.content.Context) -> 151 | 1531:1540:boolean performClick() -> performClick 152 | 1546:1566:void setSelected(boolean) -> setSelected 153 | 1570:1573:void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent) -> onInitializeAccessibilityEvent 154 | 1577:1580:void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo) -> onInitializeAccessibilityNodeInfo 155 | 1584:1646:void onMeasure(int,int) -> onMeasure 156 | 1649:1653:void setTab(android.support.design.widget.TabLayout$Tab) -> a 157 | 1656:1658:void reset() -> a 158 | 1661:1724:void update() -> b 159 | 1728:1770:void updateTextAndIcon(android.widget.TextView,android.widget.ImageView) -> a 160 | 1780:1780:float approximateLineWidth(android.text.Layout,int,float) -> a 161 | com.zhihu.android.app.ui.activity.MainActivity -> com.zhihu.android.app.ui.activity.MainActivity: 162 | 1189:1196:void onTabReselected(android.support.design.widget.TabLayout$Tab) -> c 163 | --------------------------------------------------------------------------------