📄 decompile5.c
字号:
/* take a stack, turn it into a tree. e.g.: cmd stack push 'a' 'a' push 'a' 'a' 'a' getvar 'a' a push '1' 'a' a 1 add 'a' a+1 setvar a = a+1*/#include <assert.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <math.h>#include "decompile.h"#include "read.h"#include "action.h"#define puts(s) fputs((s),stdout)static int gIndent;typedef enum{ BRANCH_NONE = 0, BRANCH_WHILE, BRANCH_DO, BRANCH_IF, BRANCH_ELSE} Branchtype;static int readStatements(FILE *f, int length, Stack **slist);void decompileStatements(Stack *statements, int n);static void listItem(Stack s, Action parent);static void resolveOffsets(Stack *statements, int nStatements);static void untangleBranches(Stack *statements, int start, int stop, Branchtype type, int indent);static Stack negateExpression(Stack s);char **dictionary;Stack reg0;static int isNum(char *s){ float f = atof(s); if(f != 0 || s[0] == '0') return true; else return false;}int intVal(Stack s){ if(s->type == 'i') return s->data.inum; if(s->type == 'd') return (int)floor(s->data.dnum); if(s->type == 's') return atoi(s->data.string); if(s->type == 't') error("Can't call intVal on a tree!"); return 0;}static Stack stack = NULL;static Stack newStack(){ Stack s = (Stack)malloc(sizeof(struct _stack)); memset(s, 0, sizeof(struct _stack)); s->target = -1; return s;}static void destroyTree(Stack s){ if(!s) return; if(s->type == 't') { destroyTree(s->data.tree->left); destroyTree(s->data.tree->right); free(s->data.tree); } else if(s->type == 's') free(s->data.string); free(s);}static void destroy(Stack s){ if(!s) return; if(s->type == 't') free(s->data.tree); else if(s->type == 's') free(s->data.string); free(s);}#define min(a,b) (((a)<(b))?(a):(b))/* XXX - this is lame nomenclature */static Stack newTreeBase(Stack left, Action action, Stack right){ Tree t = (Tree)malloc(sizeof(struct _tree)); Stack s = newStack(); t->left = left; t->right = right; t->action = action; s->type = 't'; s->data.tree = t; return s;}static Stack newTree(Stack left, Action action, Stack right){ Stack s = newTreeBase(left, action, right); /* propagate offset values- tree head should have offset = min of its children */ if(left == NULL) { if(right == NULL) s->offset = 0; else s->offset = right->offset; } else { if(right == NULL) s->offset = left->offset; else s->offset = min(left->offset, right->offset); } return s;}static Stack newString(const char *string){ Stack s = newStack(); s->type = 's'; s->data.string = string; return s;}static Stack newDouble(double d){ Stack s = newStack(); s->type = 'd'; s->data.dnum = d; return s;}static Stack newInteger(int i){ Stack s = newStack(); s->type = 'i'; s->data.inum = i; return s;}static Stack newProperty(Property prop){ Stack s = newStack(); s->type = 'p'; s->data.prop = prop; return s;}static Stack pop(){ Stack s = stack; if(!stack) error("blown stack!"); stack = stack->next; return s;}static void push(Stack s){ s->next = stack; stack = s;}static char *negateString(char *s){ int i, l = strlen(s)+1; char *New = realloc(s, l+1); for(i=l; i>0; --i) New[i] = New[i-1]; New[0] = '-'; return New;}/* looks like setProperty has been replaced by setMember in F5 but it still uses the pushdata property type */static Property getSetProperty(int prop){ switch(prop) { case SWF_SETPROPERTY_X: return PROPERTY_X; case SWF_SETPROPERTY_Y: return PROPERTY_Y; case SWF_SETPROPERTY_XSCALE: return PROPERTY_XSCALE; case SWF_SETPROPERTY_YSCALE: return PROPERTY_YSCALE; case SWF_SETPROPERTY_ALPHA: return PROPERTY_ALPHA; case SWF_SETPROPERTY_VISIBILITY: return PROPERTY_VISIBLE; case SWF_SETPROPERTY_ROTATION: return PROPERTY_ROTATION; case SWF_SETPROPERTY_NAME: return PROPERTY_NAME; case SWF_SETPROPERTY_HIGHQUALITY: return PROPERTY_HIGHQUALITY; case SWF_SETPROPERTY_SHOWFOCUSRECT: return PROPERTY_FOCUSRECT; case SWF_SETPROPERTY_SOUNDBUFFERTIME: return PROPERTY_SOUNDBUFTIME; default: return -1; }}static Stack readActionRecord(FILE *f){ int length = 0, type = readUInt8(f); if((type&0x80) == 0x80) length = readUInt16(f); switch(type) { case SWFACTION_POP: return newTree(NULL, type, NULL); /* return NULL; */ /* no-arg */ case SWFACTION_GETTIMER: case SWFACTION_STOPDRAGMOVIE: case SWFACTION_NEXTFRAME: case SWFACTION_PREVFRAME: case SWFACTION_PLAY: case SWFACTION_STOP: case SWFACTION_TOGGLEQUALITY: case SWFACTION_STOPSOUNDS: return newTree(NULL, type, NULL); /* one-arg */ case SWFACTION_STRINGLENGTH: case SWFACTION_INT: case SWFACTION_RANDOM: case SWFACTION_MBLENGTH: case SWFACTION_ORD: case SWFACTION_CHR: case SWFACTION_MBORD: case SWFACTION_MBCHR: case SWFACTION_LOGICALNOT: case SWFACTION_GETVARIABLE: case SWFACTION_REMOVECLIP: case SWFACTION_TRACE: case SWFACTION_SETTARGETEXPRESSION: case SWFACTION_CALLFRAME: return newTree(pop(), type, NULL); /* two-arg */ case SWFACTION_ADD: case SWFACTION_MULTIPLY: case SWFACTION_DIVIDE: case SWFACTION_EQUAL: case SWFACTION_LESSTHAN: case SWFACTION_LOGICALAND: case SWFACTION_LOGICALOR: case SWFACTION_STRINGEQ: case SWFACTION_STRINGCONCAT: case SWFACTION_STRINGCOMPARE: { Stack right = pop(); Stack left = pop(); return newTree(left, type, right); } case SWFACTION_SETVARIABLE: { Stack right = pop(); Stack left = pop(); if(right->type == 't' && right->data.tree->action == SWFACTION_SETREGISTER) { /* copy tree to register so we can use it on getregister */ /* and remove the register bit so we don't loop endlessly */ reg0 = newTree(left, type, right->data.tree->right); destroy(right); return NULL; } else return newTree(left, type, right); } case SWFACTION_GETPROPERTY: { Stack right = pop(); Stack left = pop(); if(right->type == 's') { Stack New = newProperty(atoi(right->data.string)); destroy(right); right = New; } return newTree(left, type, right); } case SWFACTION_SUBTRACT: { Stack right = pop(); Stack left = pop(); /* XXX - shouldn't we move this to listArithmetic? */ if(left->type == 's' && strcmp(left->data.string, "0") == 0) { destroy(left); right->data.string = negateString(right->data.string); return right; } return newTree(left, type, right); } /* three-arg */ case SWFACTION_SETPROPERTY: { Stack value = pop(); Stack property = pop(); Stack target = pop(); if(property->type == 's') { Stack New = newProperty(atoi(property->data.string)); destroy(property); property = New; } return newTree(newTree(target, type, property), SWFACTION_SETVARIABLE, value); } case SWFACTION_MBSUBSTRING: case SWFACTION_SUBSTRING: { Stack s3 = pop(); Stack s2 = pop(); Stack s1 = pop(); return newTree(s1, type, newTree(s2, type, s3)); } case SWFACTION_DUPLICATECLIP: { Stack level = pop(); Stack target = pop(); Stack source = pop(); Stack arg; if(level->type == 'i' && level->data.inum >= DUPCLIP_NUMBER) { arg = level; arg->data.inum -= DUPCLIP_NUMBER; } else { if(level->type != 't' || (level->data.tree->action != SWFACTION_ADD && level->data.tree->action != SWFACTION_NEWADD)) error("magic number 0x4000 not found in duplicateClip target level!"); if(level->data.tree->left->type == 'i' && level->data.tree->left->data.inum == DUPCLIP_NUMBER) { arg = level->data.tree->right; level->data.tree->right = NULL; } else if(level->data.tree->right->type == 'i' && level->data.tree->right->data.inum == DUPCLIP_NUMBER) { arg = level->data.tree->left; level->data.tree->left = NULL; } else error("magic number 0x4000 not found in duplicateClip target level!"); destroy(level); } return newTree(source, type, newTree(target, type, arg)); } /* weird ops */ case SWFACTION_STARTDRAGMOVIE: { Stack target = pop(); Stack lockmouse = pop(); Stack constraint = pop(); if(constraint->type == 't') error("Sorry, decompiler can't deal with conditional constraint in dragMovie!"); if(intVal(constraint) == 0) return newTree(constraint, type, newTree(lockmouse, type, target)); else { Stack p4 = pop(); Stack p3 = pop(); Stack p2 = pop(); Stack p1 = pop(); return newTree(newTree(newTree(p1, type, p2), type, newTree(p3, type, p4)), type, newTree(lockmouse, type, target)); } } case SWFACTION_PUSHDATA: { Stack s = NULL; int end = fileOffset + length; int type; int off = fileOffset - 3; /* save statement offset */ while(fileOffset < end) { if(s != NULL) push(s); switch(type = readUInt8(f)) { case 0: /* string */ s = newString(readString(f)); break; case 1: /* property - not used? */ readUInt16(f); /* 0x0000 */ s = newProperty(getSetProperty(readUInt16(f))); break; case 2: /* null? */ s = newString("NULL"); break; case 3: /* ??? */ s = newString("data type 0x03 (?)"); break; case 4: /* register? */ if(readUInt8(f) != 0) error("Sorry, can't deal with other than reg0!"); s = reg0; s->offset = reg0->offset; // reg0 = NULL; break; case 5: /* boolean? */ s = newString((readUInt8(f) == 0) ? "false" : "true"); break; case 6: /* double */ s = newDouble(readDouble(f)); break; case 7: /* int */ s = newInteger(readSInt32(f)); break; case 8: /* dictionary ref */ s = newString(dictionary[readUInt8(f)]); break; default: error("Unknown data type %i", type); } if(s->offset == 0) s->offset = off; } return s; } case SWFACTION_GOTOFRAME: return newTreeBase((Stack)readUInt16(f), type, NULL); case SWFACTION_GETURL: { char *url = readString(f); char *target = readString(f); return newTreeBase((Stack)url, type, (Stack)target); } case SWFACTION_GETURL2: { Stack target = pop(); Stack url = pop(); Stack s = newTree(url, type, target); Stack t = newTreeBase((Stack)readUInt8(f), type, s); t->offset = s->offset; return t; } case SWFACTION_WAITFORFRAMEEXPRESSION: return newTreeBase((Stack)readUInt8(f), type, NULL); case SWFACTION_GOTOEXPRESSION: { Stack s = pop(); Stack t = newTreeBase(s, type, (Stack)readUInt8(f)); t->offset = s->offset; return t; } case SWFACTION_SETTARGET: case SWFACTION_GOTOLABEL: return newTreeBase((Stack)readString(f), type, NULL); /* branches */ case SWFACTION_BRANCHIFTRUE: { Stack s = pop(), t; int offset = readSInt16(f); Action action; /* if there's a dup or !dup in the condition, we've got an || or && */ /* XXX - silly hackery wrapping things in nots so the untangler recognises it. Would be nice to clean up. */ if(s->type == 't' && ((action = s->data.tree->action) == SWFACTION_DUP || /* it's an or */ ((action = s->data.tree->action) == SWFACTION_LOGICALNOT && /* and */ s->data.tree->left->type == 't' && s->data.tree->left->data.tree->action == SWFACTION_DUP))) { int start = fileOffset; /* we're at the start of the next statement */ int off; int end = start+offset; /* should be a logical not statement */ if(action == SWFACTION_DUP) push(newTree(s, SWFACTION_LOGICALOR, NULL)); else { push(newTree(s->data.tree->left, SWFACTION_LOGICALAND, NULL)); destroy(s); } /* now grab statements between here and end */ while(fileOffset < end) { if(feof(f)) break; off = fileOffset; if((s = readActionRecord(f)) != NULL) { push(s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -