1 /*
2 flasm, command line assembler & disassembler of flash actionscript bytecode
3 Copyright (c) 2001 Opaque Industries, (c) 2002-2007 Igor Kogan, (c) 2005 Wang Zhen
4 All rights reserved. See LICENSE.TXT for terms of use.
5 */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <math.h>
13 #include <time.h>
14
15 #ifdef MEMWATCH
16 #include "memwatch.h"
17 #endif
18
19 #include "util.h"
20 #include "action.h"
21
22 void disassembleSWF(FILE *f, char *fname);
23 void skipProtected(FILE *f, unsigned long int length);
24
25 extern void tellUser(int isError, char *s, ...);
26
27 static int indent = 1;
28 static int targetIndent = 0;
29 static long int swfabspos = -1;
30 static long int swfrelpos = -1;
31
32 extern int swfVersion;
33
34 static int showLiterals;
35 static int nDict = 0;
36 struct _dict {
37 char *value;
38 int count;
39 };
40 static struct _dict dictionary[MAX_CONSTANTS];
41 static char *flasmDict = NULL;
42
43 static long int numLabels = 0;
44 static long int curLabel = 0;
45 static unsigned long int *labels = NULL;
46
47 static unsigned long int conststart = 0, constend = 0;
48
49 /* from flasm.c */
50 extern int mode;
51 extern char wasCompressed;
52
53 /* from flasm.c <- flasm.ini */
54 extern int showoffset, hexoffset, literalregisters, literalconstants;
55
56 enum {
57 eventLoad = 0x01,
58 eventEnterFrame = 0x02,
59 eventUnload = 0x04,
60 eventMouseMove = 0x08,
61 eventMouseDown = 0x10,
62 eventMouseUp = 0x20,
63 eventKeyDown = 0x40,
64 eventKeyUp = 0x80,
65 eventData = 0x100,
66 eventInitialize = 0x200, /* flash 6/7 only; flash 5 stores smartClip parameters in eventLoad */
67 eventPress = 0x400,
68 eventRelease = 0x800,
69 eventReleaseOutside = 0x1000,
70 eventRollOver = 0x2000,
71 eventRollOut = 0x4000,
72 eventDragOver = 0x8000,
73 eventDragOut = 0x10000,
74 eventKeyPress = 0x20000,
75 eventConstruct = 0x40000 /* flash 7 only */
76 };
77
78 enum {
79 IdleToOverUp = 0x01,
80 OverUpToIdle = 0x02,
81 OverUpToOverDown = 0x04,
82 OverDownToOverUp = 0x08,
83 OverDownToOutDown = 0x10,
84 OutDownToOverDown = 0x20,
85 OutDownToIdle = 0x40,
86 IdleToOverDown = 0x80,
87 OverDownToIdle = 0x100
88 };
89
90 enum {
91 keyLeft = 1,
92 keyRight = 2,
93 keyHome = 3,
94 keyEnd = 4,
95 keyInsert = 5,
96 keyDelete = 6,
97 keyBackspace = 8,
98 keyEnter = 13,
99 keyUp = 14,
100 keyDown = 15,
101 keyPageUp = 16,
102 keyPageDown = 17,
103 keyTab = 18,
104 keyEscape = 19,
105 keySpace = 32
106 };
107
108 /* names of automatic values for function2 */
109 char *arNames[] = {"this", "arguments", "super", "_root", "_parent", "_global"};
110 /* preload flags set for particular automatic value */
111 unsigned int arPreFlags[] = {0x0001, 0x0004, 0x0010, 0x0040, 0x0080, 0x0100};
112 /* suppress flags set for particular automatic value */
113 unsigned int arSupFlags[] = {0x0002, 0x0008, 0x0020, 0x0000, 0x0000, 0x0000};
114
115
skipProtected(FILE * f,unsigned long int length)116 void skipProtected(FILE *f, unsigned long int length)
117 {
118 if (fseek(f, length, SEEK_CUR) != 0)
119 tellUser(1, "Unexpected end of file");
120 }
121
printIndent(int i)122 static void printIndent(int i)
123 {
124 size_t buflen = INDENT_LEVEL*i;
125 static long int lastpos = 0;
126 long int swfpos;
127
128 if (showoffset > 0) {
129 if (showoffset == 1)
130 swfpos = swfrelpos;
131 else
132 swfpos = swfabspos+swfrelpos;
133
134 /* don't print adress if unchanged */
135 if (swfpos >= 0 && (swfpos > lastpos || swfpos == 0)) {
136 lastpos = swfpos;
137 if (hexoffset == 1)
138 /* big endian issues? */
139 printf("%04X%04X", (unsigned int) (0xFFFF & (swfpos>>16)), (unsigned int) (0xFFFF & swfpos));
140 else
141 printf("%08li", swfpos);
142 }
143 else
144 buflen += 8;
145 }
146
147 if (i>0) {
148 char buf[buflen];
149 memset(buf, ' ', buflen);
150 fwrite(buf, sizeof(char), buflen, stdout);
151 }
152 }
153
print(char * s,...)154 static void print(char *s, ...)
155 {
156 va_list ap;
157
158 printIndent(indent);
159
160 va_start(ap, s);
161 vprintf(s, ap);
162 va_end(ap);
163 }
164
printstr(char * str)165 static void printstr(char *str)
166 {
167 char buf[strlen(str)*2+3];
168 char *bufp = buf, *bufstr = str;
169
170 *bufp++ = '\'';
171 while (*bufstr++ != '\0') {
172 switch (*(bufstr-1)) {
173 case '\b':
174 *bufp++ = '\\'; *bufp++ = 'b';
175 break;
176 case '\t':
177 *bufp++ = '\\'; *bufp++ = 't';
178 break;
179 case '\n':
180 *bufp++ = '\\'; *bufp++ = 'n';
181 break;
182 case '\f':
183 *bufp++ = '\\'; *bufp++ = 'f';
184 break;
185 case '\r':
186 *bufp++ = '\\'; *bufp++ = 'r';
187 break;
188 case '\'':
189 *bufp++ = '\\'; *bufp++ = '\'';
190 break;
191 case '\\':
192 *bufp++ = '\\';
193 *bufp++ = '\\';
194 break;
195 default:
196 *bufp++ = *(bufstr-1);
197 }
198 }
199 *bufp++ = '\'';
200 fwrite(buf, sizeof(char), bufp-buf, stdout);
201 }
202
printFloat(float f,int intCast)203 static void printFloat(float f, int intCast)
204 {
205 char s[60];
206 char *sp, *xpn;
207
208 if (f != f)
209 printf("_NANF");
210 else if (f == (1.0f / 0.0f))
211 printf("POSITIVE_INFINITYF");
212 else if (f == (-1.0f / 0.0f))
213 printf("NEGATIVE_INFINITYF");
214 else {
215 sprintf(s, "%#g", (double) f);
216
217 if ((xpn = strchr(s, 'e')) == NULL)
218 sp = s + strlen(s) - 1;
219 else
220 sp = xpn - 2;
221
222 while (*sp == '0')
223 --sp;
224
225 if (intCast == 1) {
226 if (*sp == '.')
227 --sp;
228 *(sp + 1) = '\0';
229 printf("%s", s);
230 }
231 else {
232 if (*sp == '.')
233 *++sp = '0';
234 *++sp = '\0';
235 printf("%s", s);
236 if (xpn != NULL)
237 printf("%s", xpn);
238 putchar('f');
239 }
240 }
241 }
242
243 static unsigned int bitPos;
244 static unsigned int bitBuf;
245
InitBits(FILE * f)246 static void InitBits(FILE *f)
247 {
248 bitPos = 8;
249 bitBuf = ((unsigned int) fgetc(f)) & 0xff;
250 }
251
getBits(FILE * f,unsigned int n)252 static unsigned int getBits(FILE *f, unsigned int n)
253 {
254 unsigned long int v = 0;
255
256 while (n > bitPos) {
257 n -= bitPos;
258 v |= bitBuf << n;
259 bitBuf = ((unsigned int) fgetc(f)) & 0xff;
260 bitPos = 8;
261 }
262
263 bitPos -= n;
264 v |= bitBuf >> bitPos;
265 bitBuf &= 0xff >> (8 - bitPos);
266 /* never need more than 16 bits */
267 return (unsigned int) v & 0xffff;
268 }
269
printFrameNum(unsigned int frameNum)270 static void printFrameNum(unsigned int frameNum)
271 {
272 printf("\n");
273 printIndent(indent);
274 printf("frame %u\n", frameNum);
275 }
276
addLabel(unsigned long int offset)277 static void addLabel(unsigned long int offset)
278 {
279 long int i;
280
281 for (i = 0; i < numLabels; ++i) {
282 if (labels[i] == offset)
283 return;
284 }
285
286 SUREALLOC(numLabels, labels, sizeof (unsigned long int));
287
288 if (labels == NULL)
289 tellUser(1, "Not enough memory to store all labels");
290
291 labels[numLabels++] = offset;
292 }
293
294 static void processASMLine(char *line);
295
includeFile(const char * ifilename)296 static void includeFile(const char *ifilename)
297 {
298 FILE *ifile;
299 char buf[256];
300
301 while (*ifilename == ' ' || *ifilename == '\t')
302 ifilename++;
303
304 if ((ifile = fopen(ifilename, "rt")) == NULL)
305 tellUser(1, "Couldn't include file: %s", ifilename);
306
307 printf("\n// start of %s\n", ifilename);
308
309 while (fgets(buf, 256, ifile))
310 processASMLine(buf);
311
312 printf("\n// end of %s\n", ifilename);
313
314 fclose(ifile);
315 }
316
processASMLine(char * line)317 static void processASMLine(char *line)
318 {
319 char *ci = strIstr(line, "constants ");
320 char *fi = strIstr(line, "#include ");
321
322 if ((ci == NULL) || (constend == 0) || !showLiterals) {
323 /* line contains no 'constants' or prev constant declaration absent */
324 /* or multiple/broken constant pools found in action block */
325 if (fi != NULL)
326 includeFile(fi + 9);
327 else
328 printf("%s", line);
329 }
330 else if (flasmDict == NULL) {
331 /* start dict */
332 flasmDict = strdup(ci + 10);
333 }
334 else {
335 /* add user constants */
336 flasmDict = realloc(flasmDict, strlen(flasmDict) + strlen(ci + 10) + 3);
337 strcat(flasmDict, ", ");
338 strcat(flasmDict, ci + 10);
339 }
340 }
341
checkLabel(unsigned long int addr)342 static void checkLabel(unsigned long int addr)
343 {
344 if (curLabel < numLabels) {
345 while (addr > labels[curLabel]) {
346 printIndent(indent-1);
347 printf(" %s%li: // Wild label in the middle of an action, now placed before next action\n", mode < MODE_UPDATE ? "label" : "lbl", ++curLabel);
348 tellUser(0, "Branch into the middle of an action, %s%li (off by %i bytes) is placed before next action", mode < MODE_UPDATE ? "label" : "lbl", curLabel, (int)(addr - labels[curLabel-1]));
349 }
350 if (addr == labels[curLabel]) {
351 printIndent(indent-1);
352 /* make sure generated labels don't match user labels */
353 printf(" %s%li:\n", mode < MODE_UPDATE ? "label" : "lbl", ++curLabel);
354 }
355 }
356 }
357
358 static byte *buffer;
359
360 static void printActionRecord(byte *p, Action type, unsigned int *lenptr, char **regtable);
361
printActions(byte * p,unsigned long int length,unsigned long int maxActions,char ** regtable)362 static unsigned long int printActions(byte *p, unsigned long int length, unsigned long int maxActions, char **regtable)
363 {
364 /*
365 processes also nested blocks like 'function', 'with', and 'ifFrameLoaded'
366 stops at given length (in bytes) or after given numActions
367 give ANY_VALUE as parameter, if one of them is unused
368 */
369 unsigned long int i = 0;
370 unsigned long int curAction = 0;
371 unsigned int blocklen;
372
373 while ((i < length) && (curAction < maxActions)) {
374 Action type = (Action) p[i];
375
376 checkLabel(p + i - buffer);
377 swfrelpos = p + i - buffer;
378
379 ++i;
380
381 if ((type & 0x80) != 0) {
382 blocklen = S16(p + i);
383 i += 2;
384 }
385 else
386 blocklen = 0;
387
388 if (i+blocklen <= length)
389 printActionRecord(p + i, type, &blocklen, regtable);
390 else {
391 tellUser(0, "Disassembly may be incomplete: wrong action length encountered");
392 return length;
393 }
394
395 i += blocklen;
396 curAction++;
397 }
398
399 checkLabel(p + i - buffer);
400
401 return i;
402 }
403
printActionRecord(byte * p,Action type,unsigned int * lenptr,char ** regtable)404 static void printActionRecord(byte *p, Action type, unsigned int *lenptr, char **regtable)
405 {
406 unsigned int len = *lenptr;
407
408 switch (type) {
409 case SWFACTION_ADD:
410 print("oldAdd\n");
411 break;
412 case SWFACTION_SUBTRACT:
413 print("subtract\n");
414 break;
415 case SWFACTION_MULTIPLY:
416 print("multiply\n");
417 break;
418 case SWFACTION_DIVIDE:
419 print("divide\n");
420 break;
421 case SWFACTION_EQUALS:
422 print("oldEquals\n");
423 break;
424 case SWFACTION_LESSTHAN:
425 print("oldLessThan\n");
426 break;
427 case SWFACTION_LOGICALAND:
428 print("and\n");
429 break;
430 case SWFACTION_LOGICALOR:
431 print("or\n");
432 break;
433 case SWFACTION_LOGICALNOT:
434 print("not\n");
435 break;
436 case SWFACTION_STRINGEQ:
437 print("stringEq\n");
438 break;
439 case SWFACTION_STRINGLENGTH:
440 print("stringLength\n");
441 break;
442 case SWFACTION_SUBSTRING:
443 print("substring\n");
444 break;
445 case SWFACTION_INT:
446 print("int\n");
447 break;
448 case SWFACTION_POP:
449 print("pop\n");
450 break;
451 case SWFACTION_SWAP:
452 print("swap\n");
453 break;
454 case SWFACTION_INITOBJECT:
455 print("initObject\n");
456 break;
457 case SWFACTION_INITARRAY:
458 print("initArray\n");
459 break;
460 case SWFACTION_GETVARIABLE:
461 print("getVariable\n");
462 break;
463 case SWFACTION_SETVARIABLE:
464 print("setVariable\n");
465 break;
466 case SWFACTION_STRINGCONCAT:
467 print("concat\n");
468 break;
469 case SWFACTION_GETPROPERTY:
470 print("getProperty\n");
471 break;
472 case SWFACTION_SETPROPERTY:
473 print("setProperty\n");
474 break;
475 case SWFACTION_DUPLICATECLIP:
476 print("duplicateClip\n");
477 break;
478 case SWFACTION_REMOVECLIP:
479 print("removeClip\n");
480 break;
481 case SWFACTION_TRACE:
482 print("trace\n");
483 break;
484 case SWFACTION_STARTDRAGMOVIE:
485 print("startDrag\n");
486 break;
487 case SWFACTION_STOPDRAGMOVIE:
488 print("stopDrag\n");
489 break;
490 case SWFACTION_STRINGLESSTHAN:
491 print("stringLessThan\n");
492 break;
493 case SWFACTION_STRINGGREATERTHAN:
494 print("stringGreaterThan\n");
495 break;
496 case SWFACTION_RANDOM:
497 print("random\n");
498 break;
499 case SWFACTION_MBLENGTH:
500 print("mbLength\n");
501 break;
502 case SWFACTION_ORD:
503 print("ord\n");
504 break;
505 case SWFACTION_CHR:
506 print("chr\n");
507 break;
508 case SWFACTION_GETTIMER:
509 print("getTimer\n");
510 break;
511 case SWFACTION_MBSUBSTRING:
512 print("mbSubstring\n");
513 break;
514 case SWFACTION_MBORD:
515 print("mbOrd\n");
516 break;
517 case SWFACTION_MBCHR:
518 print("mbChr\n");
519 break;
520 case SWFACTION_NEXTFRAME:
521 print("nextFrame\n");
522 break;
523 case SWFACTION_PREVFRAME:
524 print("prevFrame\n");
525 break;
526 case SWFACTION_PLAY:
527 print("play\n");
528 break;
529 case SWFACTION_STOP:
530 print("stop\n");
531 break;
532 case SWFACTION_TOGGLEQUALITY:
533 print("toggleQuality\n");
534 break;
535 case SWFACTION_STOPSOUNDS:
536 print("stopSounds\n");
537 break;
538
539 /* ops with args */
540 case SWFACTION_PUSHDATA:
541 {
542 byte pushtype;
543 byte *start = p;
544 long int pushstart;
545 int n = 0;
546
547 /* may need to go back and erase push while processing flasm macros */
548 pushstart = ftell(stdout);
549
550 print("push ");
551
552 while (p < start + len) {
553 switch (pushtype = *p++) {
554 case 0: /* string */
555 {
556 char *d = (char *) p;
557
558 if (mode >= MODE_UPDATE && (Action) start[len] == SWFACTION_POP) {
559 fseek(stdout, pushstart, SEEK_SET); /* go back to overwrite 'push' */
560 processASMLine(d);
561 p = start + len; /* skip to the end of push statement */
562 *lenptr += 1;
563 }
564 else {
565 printf("%s", n++ > 0 ? ", " : "");
566 printstr(d);
567 p += strlen(d) + 1;
568 }
569 break;
570 }
571
572 case 1: /* float, used by flash for properties only */
573 {
574 float f;
575 double prop;
576
577 if (byteorder == FLASM_BIG_ENDIAN) {
578 byte *fp = (byte *) (&f);
579
580 fp[0] = p[3];
581 fp[1] = p[2];
582 fp[2] = p[1];
583 fp[3] = p[0];
584 }
585 else
586 f = *(float *) p;
587
588 printf("%s", (n++ > 0) ? ", " : "");
589
590 if (modf((double) f, &prop) == 0) { /* integer, most likely property */
591 switch ((int) prop) {
592 case 0:
593 printf("X_PROPERTY");
594 break;
595 case 1:
596 printf("Y_PROPERTY");
597 break;
598 case 2:
599 printf("XSCALE_PROPERTY");
600 break;
601 case 3:
602 printf("YSCALE_PROPERTY");
603 break;
604 case 4:
605 printf("CURRENTFRAME_PROPERTY");
606 break;
607 case 5:
608 printf("TOTALFRAMES_PROPERTY");
609 break;
610 case 6:
611 printf("ALPHA_PROPERTY");
612 break;
613 case 7:
614 printf("VISIBLE_PROPERTY");
615 break;
616 case 8:
617 printf("WIDTH_PROPERTY");
618 break;
619 case 9:
620 printf("HEIGHT_PROPERTY");
621 break;
622 case 10:
623 printf("ROTATION_PROPERTY");
624 break;
625 case 11:
626 printf("TARGET_PROPERTY");
627 break;
628 case 12:
629 printf("FRAMESLOADED_PROPERTY");
630 break;
631 case 13:
632 printf("NAME_PROPERTY");
633 break;
634 case 14:
635 printf("DROPTARGET_PROPERTY");
636 break;
637 case 15:
638 printf("URL_PROPERTY");
639 break;
640 case 16:
641 printf("HIGHQUALITY_PROPERTY");
642 break;
643 case 17:
644 printf("FOCUSRECT_PROPERTY");
645 break;
646 case 18:
647 printf("SOUNDBUFTIME_PROPERTY");
648 break;
649 case 19:
650 printf("QUALITY_PROPERTY");
651 break;
652 case 20:
653 printf("XMOUSE_PROPERTY");
654 break;
655 case 21:
656 printf("YMOUSE_PROPERTY");
657 break;
658 default:
659 printFloat(f, 0);
660 }
661 }
662 else
663 printFloat(f, 0);
664
665 p += 4;
666 break;
667 }
668
669 case 2:
670 /* null */
671 printf("%sNULL", (n++ > 0) ? ", " : "");
672 break;
673
674 case 3:
675 /* undefined */
676 printf("%sUNDEF", (n++ > 0) ? ", " : "");
677 break;
678
679 case 4:
680 /* register */
681 if (n++ > 0)
682 printf(", ");
683 if (literalregisters && regtable != NULL && regtable[*p] != NULL && *regtable[*p] != '\0') {
684 if (goodID(regtable[*p]))
685 printf("r:%s", regtable[*p]);
686 else
687 printf("r:'%s'", regtable[*p]);
688 }
689 else {
690 printf("r:%i", *p);
691 }
692 p++;
693 break;
694
695 case 5:
696 /* boolean */
697 if (*p++)
698 printf("%sTRUE", (n++ > 0) ? ", " : "");
699 else
700 printf("%sFALSE", (n++ > 0) ? ", " : "");
701 break;
702
703 case 6:
704 /* double */
705 {
706 double d;
707 byte *dp = (byte *) (&d);
708 char s[100];
709 char *sp, *xpn;
710
711 if (byteorder == FLASM_BIG_ENDIAN) {
712 dp[0] = p[3];
713 dp[1] = p[2];
714 dp[2] = p[1];
715 dp[3] = p[0];
716 dp[4] = p[7];
717 dp[5] = p[6];
718 dp[6] = p[5];
719 dp[7] = p[4];
720 }
721 else {
722 dp[0] = p[4];
723 dp[1] = p[5];
724 dp[2] = p[6];
725 dp[3] = p[7];
726 dp[4] = p[0];
727 dp[5] = p[1];
728 dp[6] = p[2];
729 dp[7] = p[3];
730 }
731
732 /* the old way without '1.5e-24'-like notation
733 fprec = 15-floor(log10(fabs(d)));
734 sprintf(s,"%.*f",fprec,d); */
735
736 printf("%s", (n++ > 0) ? ", " : "");
737
738 if (d == 0) {
739 if (mode < MODE_UPDATE)
740 printf("0.0");
741 else
742 printf("0"); /* save some bytes in update mode - integer instead of double */
743 }
744 else if (d != d)
745 printf("_NAN");
746 else if (d == (1.0 / 0.0))
747 printf("POSITIVE_INFINITY");
748 else if (d == (-1.0 / 0.0))
749 printf("NEGATIVE_INFINITY");
750 else {
751 sprintf(s, "%#.*g", 16, d);
752
753 if ((xpn = strchr(s, 'e')) == NULL)
754 sp = s + strlen(s) - 1;
755 else
756 sp = xpn - 2; /* one digit less precision for exp form values
757 preventing MAX_NUMBER rounding to INFINITY */
758
759 while (*sp == '0') /* delete 0's at the end of the number or mantissa */
760 --sp;
761
762 if (*sp == '.') /* expand values like "1." to "1.0" */
763 *++sp = '0';
764
765 *++sp = '\0'; /* terminate buffer (exponent is cutted off) */
766
767 printf("%s", s);
768
769 if (xpn != NULL) /* if exponent here, print it */
770 printf("%s", xpn);
771 }
772
773 p += 8;
774 break;
775 }
776
777 case 7:
778 /* integer */
779 {
780 int i;
781
782 if (byteorder == FLASM_BIG_ENDIAN) {
783 byte *ip = (byte *) (&i);
784
785 ip[0] = p[3];
786 ip[1] = p[2];
787 ip[2] = p[1];
788 ip[3] = p[0];
789 }
790 else
791 i = *(int *) p;
792
793 printf("%s%i", (n++ > 0) ? ", " : "", i);
794 p += 4;
795 break;
796 }
797
798 case 8:
799 /* dictionary, 1-byte reference */
800 {
801 char *d;
802 if (showLiterals && (*p < nDict)) {
803 d = dictionary[*p].value;
804 if (mode >= MODE_UPDATE && (Action) start[len] == SWFACTION_POP) {
805 fseek(stdout, pushstart, SEEK_SET); /* go back to overwrite 'push' */
806 processASMLine(d);
807 p = start + len; /* skip to the end of push statement */
808 *lenptr += 1;
809 }
810 else {
811 printf("%s", n++ > 0 ? ", " : "");
812 printstr(d);
813 dictionary[*p].count++; /* constant used one more time */
814 p++;
815 }
816 }
817 else {
818 printf("%sc:%u", n++ > 0 ? ", " : "", *p);
819 p++;
820 }
821 break;
822 }
823
824 case 9:
825 /* dictionary, 2-byte reference */
826 {
827 char *d;
828 if (showLiterals && (S16(p) < nDict)) {
829 d = dictionary[S16(p)].value;
830 if (mode >= MODE_UPDATE && (Action) start[len] == SWFACTION_POP) {
831 fseek(stdout, pushstart, SEEK_SET); /* go back to overwrite 'push' */
832 processASMLine(d);
833 p = start + len; /* skip to the end of push statement */
834 *lenptr += 1;
835 }
836 else {
837 printf("%s", n++ > 0 ? ", " : "");
838 printstr(d);
839 dictionary[S16(p)].count++; /* constant used one more time */
840 p += 2;
841 }
842 }
843 else {
844 printf("%sc:%u", n++ > 0 ? ", " : "", S16(p));
845 p += 2;
846 }
847 break;
848 }
849
850 default:
851 printf("%s%s // unknown push type %i: rest of push skipped", (n++ > 0) ? ", " : "", "???", pushtype);
852 tellUser(0, "Unknown push type %i: rest of push skipped", pushtype);
853 p = start + len;
854 }
855 }
856
857 putchar('\n');
858
859 break;
860 }
861
862 case SWFACTION_GOTOFRAME:
863 print("gotoFrame %u\n", S16(p));
864 p += 2;
865 break;
866
867 case SWFACTION_GETURL:
868 {
869 char *url = (char *) p;
870 p += strlen(url) + 1;
871 print("getURL ");
872 printstr(url);
873 putchar(' ');
874 printstr((char *) p);
875 putchar('\n');
876 break;
877 }
878
879 case SWFACTION_BRANCHALWAYS:
880 {
881 long int l = longintBinaryFind((unsigned long int)(p + 2 + S16signed(p) - buffer), labels, numLabels);
882 if (l >= 0) {
883 print("branch %s%i", mode < MODE_UPDATE ? "label" : "lbl", l + 1, labels);
884 if (showoffset == 0)
885 putchar('\n');
886 else
887 printf(" // offset %i\n", S16signed(p));
888 }
889 else {
890 print("branch %i // branch target not found\n", S16signed(p));
891 tellUser(0, "branch target not found: %li", S16signed(p));
892 }
893 break;
894 }
895
896 case SWFACTION_BRANCHIFTRUE:
897 {
898 long int l = longintBinaryFind((unsigned long int)(p + 2 + S16signed(p) - buffer), labels, numLabels);
899 if (l >= 0) {
900 print("branchIfTrue %s%i", mode < MODE_UPDATE ? "label" : "lbl", l + 1, labels);
901 if (showoffset == 0)
902 putchar('\n');
903 else
904 printf(" // offset %i\n", S16signed(p));
905 }
906 else {
907 print("branchIfTrue %i // branch target not found\n", S16signed(p));
908 tellUser(0, "branchIfTrue target not found: %li", S16signed(p));
909 }
910 break;
911 }
912
913 case SWFACTION_GETURL2:
914 {
915 byte flags = *p;
916 switch (flags) {
917 case 0:
918 print("getURL2\n");
919 break;
920 case 1:
921 print("getURL2 GET\n");
922 break;
923 case 2:
924 print("getURL2 POST\n");
925 break;
926 case 0x40:
927 print("loadMovie\n");
928 break;
929 case 0x41:
930 print("loadMovie GET\n");
931 break;
932 case 0x42:
933 print("loadMovie POST\n");
934 break;
935 case 0x80:
936 print("loadVariablesNum\n");
937 break;
938 case 0x81:
939 print("loadVariablesNum GET\n");
940 break;
941 case 0x82:
942 print("loadVariablesNum POST\n");
943 break;
944 case 0xC0:
945 print("loadVariables\n");
946 break;
947 case 0xC1:
948 print("loadVariables GET\n");
949 break;
950 case 0xC2:
951 print("loadVariables POST\n");
952 break;
953 default:
954 print("getURL2 0x%x // unknown flag\n", flags);
955 tellUser(0, "Unknown getURL2 flag: 0x%x");
956 }
957
958 break;
959 }
960
961 case SWFACTION_CALLFRAME:
962 print("callFrame\n");
963 break;
964
965 case SWFACTION_GOTOEXPRESSION:
966 print("goto");
967 if (*p == 0)
968 puts("AndStop");
969 else if (*p == 1)
970 puts("AndPlay");
971 else if ((*p == 2) && (len == 3)) {
972 /* undocumented additional argument - the number of frames in all previous scenes */
973 p++;
974 printf("AndStop skip %u\n", S16(p));
975 }
976 else if ((*p == 3) && (len == 3)) {
977 /* undocumented additional argument - the number of frames in all previous scenes */
978 p++;
979 printf("AndPlay skip %u\n", S16(p));
980 }
981 else {
982 /* what the hell is it? assume andPlay, since flag>1 */
983 printf("AndPlay // unknown goto flag %i\n", *p);
984 tellUser(0, "Unknown goto flag %i", *p);
985 }
986 break;
987
988 case SWFACTION_IFFRAMELOADED:
989 {
990 unsigned int frame = S16(p);
991 byte frameLoadedActions;
992 p += 2;
993 print("ifFrameLoaded %u\n", frame);
994 ++indent;
995 frameLoadedActions = *p++;
996 *lenptr += printActions(p, ANY_VALUE, (unsigned long int) frameLoadedActions, regtable);
997 --indent;
998 print("end // of ifFrameLoaded %u\n\n", frame);
999 break;
1000 }
1001
1002 case SWFACTION_IFFRAMELOADEDEXPRESSION:
1003 {
1004 byte frameLoadedActions;
1005 print("ifFrameLoadedExpr\n");
1006 ++indent;
1007 frameLoadedActions = *p++;
1008 *lenptr += printActions(p, ANY_VALUE, (unsigned long int) frameLoadedActions, regtable);
1009 --indent;
1010 print("end // of ifFrameLoadedExpr\n\n");
1011 break;
1012 }
1013
1014 case SWFACTION_SETTARGET:
1015 print("setTarget '%s'\n", p);
1016 break;
1017
1018 case SWFACTION_SETTARGETEXPRESSION:
1019 print("setTargetExpr\n");
1020 break;
1021
1022 case SWFACTION_GOTOLABEL:
1023 print("gotoLabel '%s'\n", p);
1024 break;
1025
1026 case SWFACTION_END:
1027 break;
1028
1029 /* f5 ops */
1030 case SWFACTION_DELETE:
1031 print("delete\n");
1032 break;
1033 case SWFACTION_DELETE2:
1034 print("delete2\n");
1035 break;
1036 case SWFACTION_VAR:
1037 print("var\n");
1038 break;
1039 case SWFACTION_VAREQUALS:
1040 print("varEquals\n");
1041 break;
1042 case SWFACTION_CALLFUNCTION:
1043 print("callFunction\n");
1044 break;
1045 case SWFACTION_RETURN:
1046 print("return\n");
1047 break;
1048 case SWFACTION_MODULO:
1049 print("modulo\n");
1050 break;
1051 case SWFACTION_NEW:
1052 print("new\n");
1053 break;
1054 case SWFACTION_TYPEOF:
1055 print("typeof\n");
1056 break;
1057 case SWFACTION_TARGETPATH:
1058 print("targetPath\n");
1059 break;
1060 case SWFACTION_NEWADD:
1061 print("add\n");
1062 break;
1063 case SWFACTION_NEWLESSTHAN:
1064 print("lessThan\n");
1065 break;
1066 case SWFACTION_NEWEQUALS:
1067 print("equals\n");
1068 break;
1069 case SWFACTION_TONUMBER:
1070 print("toNumber\n");
1071 break;
1072 case SWFACTION_TOSTRING:
1073 print("toString\n");
1074 break;
1075 case SWFACTION_DUP:
1076 print("dup\n");
1077 break;
1078 case SWFACTION_GETMEMBER:
1079 print("getMember\n");
1080 break;
1081 case SWFACTION_SETMEMBER:
1082 print("setMember\n");
1083 break;
1084 case SWFACTION_INCREMENT:
1085 print("increment\n");
1086 break;
1087 case SWFACTION_DECREMENT:
1088 print("decrement\n");
1089 break;
1090 case SWFACTION_NEWMETHOD:
1091 print("newMethod\n");
1092 break;
1093 case SWFACTION_CALLMETHOD:
1094 print("callMethod\n");
1095 break;
1096 case SWFACTION_BITWISEAND:
1097 print("bitwiseAnd\n");
1098 break;
1099 case SWFACTION_BITWISEOR:
1100 print("bitwiseOr\n");
1101 break;
1102 case SWFACTION_BITWISEXOR:
1103 print("bitwiseXor\n");
1104 break;
1105 case SWFACTION_SHIFTLEFT:
1106 print("shiftLeft\n");
1107 break;
1108 case SWFACTION_SHIFTRIGHT:
1109 print("shiftRight\n");
1110 break;
1111 case SWFACTION_SHIFTRIGHT2:
1112 print("shiftRight2\n");
1113 break;
1114
1115 case SWFACTION_CONSTANTPOOL:
1116 {
1117 unsigned int i, n = S16(p);
1118 int willInclude = 0;
1119 unsigned int constlen = 2;
1120
1121 if (n > MAX_CONSTANTS)
1122 tellUser(0, "Too many constants");
1123
1124 p += 2;
1125 conststart = ftell(stdout);
1126 print("constants ");
1127
1128 nDict = 0;
1129
1130 for (i = 0; i < n; ++i) {
1131 if (strnIcmp((char *) p, "#include", 8) == 0)
1132 willInclude = 1;
1133
1134 dictionary[i].value = (char *) p;
1135 dictionary[i].count = 0;
1136 nDict++;
1137
1138 printstr((char *) p);
1139 if (i < n - 1)
1140 printf("%s", ", ");
1141 else
1142 printf("%s", " ");
1143
1144 constlen += strlen((char *) p) + 1;
1145 p += strlen((char *) p) + 1;
1146 }
1147
1148 if (constlen != len) {
1149 tellUser(0, "Declared constant pool length %u differs from calculated length %u", len, constlen);
1150 /* try to restore the real constant pool length */
1151 *lenptr = 0xff & constlen;
1152 *(lenptr+1) = 0xff & (constlen >> 8);
1153 }
1154
1155 printf("%s", "\n");
1156
1157 /* put some free space after constant pool to add user constants from included file later */
1158 if (mode >= MODE_UPDATE && willInclude == 1)
1159 for (i = 0; i < MAX_INCLUDE_POOL; ++i)
1160 putchar(' ');
1161
1162 constend = ftell(stdout);
1163
1164 break;
1165 }
1166
1167 case SWFACTION_WITH:
1168 {
1169 unsigned int withlen = S16(p);
1170
1171 print("with\n");
1172
1173 ++indent;
1174 printActions(p + 2, (unsigned long int) withlen, ANY_VALUE, regtable);
1175 --indent;
1176
1177 *lenptr += withlen;
1178
1179 print("end\n");
1180
1181 break;
1182 }
1183
1184 case SWFACTION_DEFINEFUNCTION:
1185 {
1186 int nargs;
1187 unsigned int funclen;
1188 char *name = (char *) p;
1189 char *argname;
1190
1191 p += strlen(name) + 1;
1192 nargs = S16(p);
1193 p += 2;
1194
1195 if (*name != '\0') {
1196 if (mode < MODE_UPDATE && goodID(name))
1197 print("function %s (", name);
1198 else
1199 print("function '%s' (", name);
1200 }
1201 else
1202 print("function (");
1203
1204 if (nargs > 0) {
1205 argname = (char *) p;
1206 printf("'%s'", argname);
1207 p += strlen(argname) + 1;
1208 --nargs;
1209 }
1210
1211 for (; nargs > 0; --nargs) {
1212 argname = (char *) p;
1213 printf(", '%s'", argname);
1214 p += strlen(argname) + 1;
1215 }
1216
1217 putchar(')');
1218 putchar('\n');
1219
1220 funclen = S16(p);
1221 p += 2;
1222
1223 ++indent;
1224 printActions(p, (unsigned long int) funclen, ANY_VALUE, NULL);
1225 --indent;
1226
1227 print("end // of function %s\n\n", name);
1228
1229 *lenptr += funclen;
1230
1231 break;
1232 }
1233
1234 case SWFACTION_ENUMERATE:
1235 print("enumerate\n");
1236 break;
1237
1238 case SWFACTION_SETREGISTER:
1239 if (literalregisters && regtable != NULL && regtable[*p] != NULL && *regtable[*p] != '\0') {
1240 if (goodID(regtable[*p]))
1241 print("setRegister r:%s\n", regtable[*p]);
1242 else
1243 print("setRegister r:'%s'\n", regtable[*p]);
1244 }
1245 else
1246 print("setRegister r:%i\n", *p);
1247 break;
1248
1249 case SWFACTION_STRICTEQUALS:
1250 print("strictEquals\n");
1251 break;
1252
1253 case SWFACTION_GREATERTHAN:
1254 print("greaterThan\n");
1255 break;
1256
1257 case SWFACTION_ENUMERATEVALUE:
1258 print("enumerateValue\n");
1259 break;
1260
1261 case SWFACTION_INSTANCEOF:
1262 print("instanceOf\n");
1263 break;
1264
1265 case SWFACTION_STRICTMODE:
1266 print("strictMode");
1267 if (*p > 0)
1268 puts(" ON");
1269 else
1270 puts(" OFF");
1271 break;
1272
1273 case SWFACTION_DEFINEFUNCTION2:
1274 {
1275 unsigned int i, funclen, nargs, autoregFlags;
1276 int firstprint = 1;
1277 byte nregisters, curautoreg;
1278 char *argnames[MAX_REGISTERS];
1279 char *name = (char *) p;
1280 memset(argnames, 0, MAX_REGISTERS * sizeof (char *));
1281
1282 p += strlen(name) + 1;
1283 nargs = S16(p);
1284 p += 2;
1285 nregisters = *p++;
1286 autoregFlags = S16(p);
1287 p += 2;
1288
1289 if (*name != '\0') {
1290 if (mode < MODE_UPDATE && goodID(name))
1291 print("function2 %s (", name);
1292 else
1293 print("function2 '%s' (", name);
1294 }
1295 else
1296 print("function2 (");
1297
1298 /* print function arguments, store links to their names in register allocation table */
1299 for (; nargs > 0; nargs--) {
1300 byte reg = *p;
1301 char *arg = (char *)(p+1);
1302
1303 if (reg != 0) {
1304 if (argnames[reg] != NULL) {
1305 tellUser (0, "Duplicate register allocation in function2 %s: %s and %s both go to r:%u", name, argnames[reg], arg, reg);
1306 }
1307 argnames[reg] = arg;
1308 printf("r:%u='%s'%s", reg, arg, nargs == 1 ? "" : ", ");
1309 }
1310 else
1311 printf("'%s'%s", arg, nargs == 1 ? "" : ", ");
1312
1313 p += strlen(arg) + 2;
1314 }
1315
1316 printf("%s", ") (");
1317
1318 /* allocate registers for "automatic" names based on flags, skip suppressed parameters */
1319 curautoreg = 1;
1320
1321 for (i = 0; i < MAX_AUTO_REGS; i++) {
1322 if ((autoregFlags & arPreFlags[i]) == arPreFlags[i]) {
1323 /* preload flag */
1324
1325 if (argnames[curautoreg] != NULL && strcmp(argnames[curautoreg], arNames[i]))
1326 tellUser (0, "Duplicate register allocation in function2 %s: %s and %s both go to r:%u", name, argnames[curautoreg], arNames[i], curautoreg);
1327 if (autoregFlags & arSupFlags[i])
1328 tellUser (0, "Preload and suppress flags are both set for %s parameter of function2 %s", arNames[i], name);
1329
1330 argnames[curautoreg] = arNames[i];
1331 autoregFlags -= arPreFlags[i];
1332 printf("%sr:%u='%s'", firstprint == 0 ? ", " : "", curautoreg, arNames[i]);
1333 firstprint = 0;
1334 curautoreg++;
1335 }
1336 else if ((autoregFlags & arSupFlags[i]) == arSupFlags[i]) {
1337 /* suppress flag */
1338 autoregFlags -= arSupFlags[i];
1339 }
1340 else {
1341 /* the parameter is neither preloaded nor suppressed */
1342 printf("%s'%s'", firstprint == 0 ? ", " : "", arNames[i]);
1343 firstprint = 0;
1344 }
1345 }
1346
1347 printf("%s", ")\n");
1348
1349 if (autoregFlags != 0)
1350 tellUser(0,"Unknown register flag for function2 %s: %u", name, autoregFlags);
1351
1352 funclen = S16(p);
1353 p += 2;
1354
1355 ++indent;
1356 printActions(p, (unsigned long int) funclen, ANY_VALUE, argnames);
1357 --indent;
1358
1359 print("end // of function %s\n\n", name);
1360
1361 *lenptr += funclen;
1362
1363 break;
1364 }
1365
1366 case SWFACTION_THROW:
1367 print("throw\n");
1368 break;
1369
1370 case SWFACTION_EXTENDS:
1371 print("extends\n");
1372 break;
1373
1374 case SWFACTION_IMPLEMENTS:
1375 print("implements\n");
1376 break;
1377
1378 case SWFACTION_CAST:
1379 print("cast\n");
1380 break;
1381
1382 case SWFACTION_FSCOMMAND2:
1383 print("FSCommand2\n");
1384 break;
1385
1386 case SWFACTION_TRY:
1387 {
1388 unsigned int trylen, catchlen, finallylen;
1389 /* try type */
1390 byte catchtype = *p++;
1391 trylen = S16(p);
1392 p += 2;
1393 catchlen = S16(p);
1394 p += 2;
1395 finallylen = S16(p);
1396 p += 2;
1397
1398 if (catchtype & 4) {
1399 /* error in register */
1400 if (literalregisters && regtable != NULL && regtable[*p] != NULL && *regtable[*p] != '\0')
1401 print("try r:%s\n", regtable[*p++]);
1402 else
1403 print("try r:%u\n", *p++);
1404 }
1405 else {
1406 /* error in variable */
1407 print("try");
1408 if (*p != '\0')
1409 printf(" '%s'", (char *) p);
1410 putchar('\n');
1411 p += len-7;
1412 }
1413
1414 ++indent;
1415 printActions(p, (unsigned long int) trylen, ANY_VALUE, regtable);
1416 --indent;
1417
1418 if (catchlen > 0) {
1419 print("catch\n");
1420 ++indent;
1421 printActions(p+trylen, (unsigned long int) catchlen, ANY_VALUE, regtable);
1422 --indent;
1423 }
1424 if (finallylen > 0) {
1425 print("finally\n");
1426 ++indent;
1427 printActions(p+trylen+catchlen, (unsigned long int) finallylen, ANY_VALUE, regtable);
1428 --indent;
1429 }
1430
1431 *lenptr += trylen+catchlen+finallylen;
1432 print("end // of try\n");
1433 break;
1434 }
1435
1436 default:
1437 print("swfAction 0x%02x", type);
1438 if (len > 0) {
1439 unsigned int i;
1440 printf("%s", " hexdata ");
1441 for (i = 0; i < len; ++i) {
1442 printf("0x%02X", *p);
1443 if (i < len - 1)
1444 printf("%s", ",");
1445 p++;
1446 }
1447 }
1448 printf("%s", " // unknown action\n");
1449 tellUser(0, "Unknown action 0x%02x", type);
1450 }
1451 return;
1452 }
1453
rebuildConstantPool(void)1454 static void rebuildConstantPool(void)
1455 {
1456 long int curpos = ftell(stdout);
1457 unsigned long int k;
1458 int i;
1459 int constOK = 0;
1460
1461 fseek(stdout, conststart, SEEK_SET); /* go back to the last constants declaration */
1462
1463 for (i = 0; i < nDict; ++i) {
1464 /* remove constants used less than 2 times, and empty strings */
1465 if ((dictionary[i].count > 1) && (strlen(dictionary[i].value) > 0)) {
1466 if (constOK == 0) {
1467 print("constants ");
1468 constOK = 1;
1469 }
1470
1471 printstr(dictionary[i].value);
1472 printf("%s", ", ");
1473 }
1474 }
1475
1476 if (flasmDict != NULL) {
1477 if (constOK == 0) {
1478 print("constants ");
1479 constOK = 1;
1480 }
1481 if (ftell(stdout) + strlen(flasmDict) >= constend)
1482 tellUser(0, "Too many user constants: %s", flasmDict);
1483 else
1484 printf("%s", flasmDict); /* add user constants */
1485 }
1486 else if (constOK == 1)
1487 fseek(stdout, -2, SEEK_CUR); /* remove last ", " */
1488
1489 putchar('\n');
1490
1491 for (k = ftell(stdout); k < constend - 1; ++k) /* fill the rest of former constants with spaces */
1492 putchar(' ');
1493
1494 putchar('\n');
1495
1496 if (flasmDict != NULL) {
1497 free(flasmDict);
1498 flasmDict = NULL;
1499 }
1500 fseek(stdout, curpos, SEEK_SET);
1501 }
1502
readActionBuffer(FILE * f,unsigned long int length)1503 static void readActionBuffer(FILE *f, unsigned long int length)
1504 {
1505 if (length == 0)
1506 return;
1507
1508 buffer = malloc(length);
1509 if (buffer == NULL)
1510 tellUser(1, "Not enough memory to process action block");
1511
1512 if (fread(buffer, 1, length, f) != length)
1513 tellUser(1, "Attempt to read beyond EOF");
1514 }
1515
createLabels(unsigned long int length)1516 static void createLabels(unsigned long int length)
1517 {
1518 unsigned long int i;
1519 unsigned int blocklen;
1520 unsigned int numpools = 0;
1521
1522 numLabels = 0;
1523 curLabel = 0;
1524 for (i = 0; i < length; ++i) {
1525 if (buffer[i] & 0x80) {
1526 blocklen = S16(buffer + i + 1);
1527
1528 if ((Action) buffer[i] == SWFACTION_BRANCHALWAYS || (Action) buffer[i] == SWFACTION_BRANCHIFTRUE) {
1529 if ((signed long int) (i + 3 + blocklen + S16signed(buffer + i + 3)) >= 0) {
1530 addLabel(i + 3 + blocklen + S16signed(buffer + i + 3));
1531 }
1532 }
1533 else if ((Action) buffer[i] == SWFACTION_CONSTANTPOOL) {
1534 byte *p = buffer + i + 3;
1535 unsigned int n, nStrings = S16(p);
1536 numpools++;
1537 p += 2;
1538 for (n = 0; n < nStrings; ++n)
1539 p += strlen((char *) p) + 1;
1540
1541 if (blocklen != p - buffer - i - 3) {
1542 /* fix broken length */
1543 blocklen = p - buffer - i - 3;
1544 }
1545 }
1546
1547 i += blocklen + 2;
1548 }
1549 }
1550 if ((numpools > 1) && (literalconstants < 2))
1551 showLiterals = 0;
1552 }
1553
printActionBlock(FILE * f,unsigned long int length,abtype abtype,unsigned int flags,byte key)1554 static void printActionBlock(FILE *f, unsigned long int length, abtype abtype, unsigned int flags, byte key)
1555 {
1556 swfabspos = ftell(f);
1557 swfrelpos = 0;
1558 conststart = constend = 0;
1559
1560 nDict = 0;
1561 showLiterals = literalconstants;
1562
1563 ++indent;
1564
1565 readActionBuffer(f, length);
1566
1567 createLabels(length);
1568
1569 qsort(labels, (size_t) numLabels, sizeof (unsigned long int), longintCompare);
1570
1571 printActions(buffer, length, ANY_VALUE, NULL);
1572
1573 if ((mode >= MODE_UPDATE) && (constend > 0) && showLiterals)
1574 rebuildConstantPool();
1575
1576 if (targetIndent == 1) {
1577 --indent;
1578 print("end\n");
1579 targetIndent = 0;
1580 }
1581
1582 --indent;
1583
1584 if (buffer != NULL) {
1585 free(buffer);
1586 buffer = NULL;
1587 }
1588
1589 if (labels != NULL) {
1590 free(labels);
1591 labels = NULL;
1592 }
1593
1594 swfabspos = -1;
1595 swfrelpos = -1;
1596 }
1597
skipMatrix(FILE * f)1598 static void skipMatrix(FILE *f)
1599 {
1600 InitBits(f);
1601 if (getBits(f, 1))
1602 getBits(f, getBits(f, 5) * 2);
1603 if (getBits(f, 1))
1604 getBits(f, getBits(f, 5) * 2);
1605 getBits(f, getBits(f, 5) * 2);
1606 }
1607
skipColorTransform(FILE * f)1608 static void skipColorTransform(FILE *f)
1609 {
1610 unsigned int needAdd, needMul, nBits;
1611 InitBits(f);
1612 needAdd = getBits(f, 1);
1613 needMul = getBits(f, 1);
1614 nBits = getBits(f, 4);
1615 if (needMul)
1616 getBits(f, nBits * 4);
1617 if (needAdd)
1618 getBits(f, nBits * 4);
1619 }
1620
skipFilters(FILE * f,byte numfilters)1621 static void skipFilters(FILE *f, byte numfilters)
1622 {
1623 while(numfilters--) {
1624 int filter = fgetc(f);
1625 switch(filter){
1626 case FILTER_DROPSHADOW:
1627 skipProtected(f, 23);
1628 break;
1629 case FILTER_BLUR:
1630 skipProtected(f, 9);
1631 break;
1632 case FILTER_GLOW:
1633 skipProtected(f, 15);
1634 break;
1635 case FILTER_BEVEL:
1636 skipProtected(f, 27);
1637 break;
1638 case FILTER_GRADIENTGLOW:
1639 skipProtected(f, fgetc(f)*5 + 19);
1640 break;
1641 case FILTER_ADJUSTCOLOR:
1642 skipProtected(f, 80);
1643 break;
1644 case FILTER_GRADIENTBEVEL:
1645 skipProtected(f, fgetc(f)*5 + 19);
1646 break;
1647 default:
1648 tellUser(1, "Unknown filter %i", filter);
1649 }
1650 }
1651 }
1652
parseKeyPressEvent(byte onKey)1653 static void parseKeyPressEvent(byte onKey)
1654 {
1655 printf("keyPress ");
1656
1657 if (onKey == keySpace)
1658 printf("_SPACE");
1659 else if (onKey == '\'')
1660 printf("'%s'", "\\'");
1661 else if (onKey == '\\')
1662 printf("'%s'", "\\\\");
1663 else if (onKey > 32)
1664 printf("'%c'", onKey);
1665 else
1666 switch (onKey) {
1667 case keyLeft:
1668 printf("_LEFT");
1669 break;
1670 case keyRight:
1671 printf("_RIGHT");
1672 break;
1673 case keyHome:
1674 printf("_HOME");
1675 break;
1676 case keyEnd:
1677 printf("_END");
1678 break;
1679 case keyInsert:
1680 printf("_INSERT");
1681 break;
1682 case keyDelete:
1683 printf("_DELETE");
1684 break;
1685 case keyBackspace:
1686 printf("_BACKSPACE");
1687 break;
1688 case keyEnter:
1689 printf("_ENTER");
1690 break;
1691 case keyUp:
1692 printf("_UP");
1693 break;
1694 case keyDown:
1695 printf("_DOWN");
1696 break;
1697 case keyPageUp:
1698 printf("_PAGEUP");
1699 break;
1700 case keyPageDown:
1701 printf("_PAGEDOWN");
1702 break;
1703 case keyTab:
1704 printf("_TAB");
1705 break;
1706 case keyEscape:
1707 printf("_ESCAPE");
1708 break;
1709 default:
1710 printf("0x%02x // unknown key", onKey);
1711 tellUser(0, "Unknown key 0x%02x in keyPress event", onKey);
1712 }
1713 }
1714
parseButtonEvent(FILE * f,unsigned int event,unsigned long int length)1715 static void parseButtonEvent(FILE *f, unsigned int event, unsigned long int length)
1716 {
1717 char delim = ' ';
1718 byte key = 0;
1719
1720 putchar('\n');
1721 ++indent;
1722 print("on");
1723
1724 if (event & IdleToOverUp) {
1725 putchar(delim);
1726 printf("idleToOverUp");
1727 delim = ',';
1728 }
1729
1730 if (event & OverUpToIdle) {
1731 putchar(delim);
1732 printf("overUpToIdle");
1733 delim = ',';
1734 }
1735
1736 if (event & OverUpToOverDown) {
1737 putchar(delim);
1738 printf("overUpToOverDown");
1739 delim = ',';
1740 }
1741
1742 if (event & OverDownToOverUp) {
1743 putchar(delim);
1744 printf("overDownToOverUp");
1745 delim = ',';
1746 }
1747
1748 if (event & OverDownToOutDown) {
1749 putchar(delim);
1750 printf("overDownToOutDown");
1751 delim = ',';
1752 }
1753
1754 if (event & OutDownToOverDown) {
1755 putchar(delim);
1756 printf("outDownToOverDown");
1757 delim = ',';
1758 }
1759
1760 if (event & OutDownToIdle) {
1761 putchar(delim);
1762 printf("outDownToIdle");
1763 delim = ',';
1764 }
1765
1766 if (event & IdleToOverDown) {
1767 putchar(delim);
1768 printf("idleToOverDown");
1769 delim = ',';
1770 }
1771
1772 if (event & OverDownToIdle) {
1773 putchar(delim);
1774 printf("overDownToIdle");
1775 delim = ',';
1776 }
1777
1778 /* keyPress */
1779 if (event > 0x1FF) {
1780 key = (byte) (event >> 9);
1781 putchar(delim);
1782 parseKeyPressEvent(key);
1783 }
1784
1785 printf("\n");
1786 printActionBlock(f, length, AB_BUTTONEVENT, event, key);
1787 print("end\n");
1788 --indent;
1789 }
1790
parseButton2(FILE * f,unsigned long int length)1791 static void parseButton2(FILE *f, unsigned long int length)
1792 {
1793 unsigned int condition, buttonID, actionOffset;
1794 unsigned long int lastABLength;
1795
1796 buttonID = getWord(f);
1797 /* trackAsMenu */
1798 fgetc(f);
1799
1800 actionOffset = getWord(f);
1801 lastABLength = length - 8 - actionOffset;
1802
1803 if (actionOffset > 0) {
1804 printf("\n");
1805 print("defineButton %u\n", buttonID);
1806
1807 /* skip button data */
1808 while (actionOffset > 2) {
1809 fgetc(f);
1810 --actionOffset;
1811 }
1812
1813 while ((actionOffset = getWord(f)) > 0) {
1814 lastABLength -= actionOffset;
1815 condition = getWord(f);
1816 parseButtonEvent(f, condition, actionOffset - 4);
1817 }
1818
1819 /* last event */
1820 condition = getWord(f);
1821 parseButtonEvent(f, condition, lastABLength);
1822
1823 print("end // of defineButton %u\n", buttonID);
1824 }
1825 else {
1826 /* no button events */
1827 while (lastABLength + 2 > 0) {
1828 fgetc(f);
1829 --lastABLength;
1830 }
1831 }
1832
1833 /* button end */
1834 fgetc(f);
1835 }
1836
printBitMasked(unsigned long int * eventptr,unsigned long int e,char * delimptr,char * str)1837 static int printBitMasked(unsigned long int *eventptr, unsigned long int e, char *delimptr, char *str)
1838 {
1839 if (*eventptr & e) {
1840 *eventptr -= e;
1841 printf("%c%s", *delimptr, str);
1842 *delimptr = ',';
1843 return 1;
1844 }
1845 else
1846 return 0;
1847 }
1848
parseEvent(FILE * f,unsigned long int event,unsigned long int length)1849 static void parseEvent(FILE *f, unsigned long int event, unsigned long int length)
1850 {
1851 byte key = 0;
1852 char delim = ' ';
1853 unsigned long int event2 = event;
1854
1855 putchar('\n');
1856 ++indent;
1857 print("onClipEvent");
1858
1859 printBitMasked(&event2, eventLoad, &delim, "load");
1860 printBitMasked(&event2, eventEnterFrame, &delim, "enterFrame");
1861 printBitMasked(&event2, eventUnload, &delim, "unload");
1862 printBitMasked(&event2, eventMouseMove, &delim, "mouseMove");
1863 printBitMasked(&event2, eventMouseDown, &delim, "mouseDown");
1864 printBitMasked(&event2, eventMouseUp, &delim, "mouseUp");
1865 printBitMasked(&event2, eventKeyDown, &delim, "keyDown");
1866 printBitMasked(&event2, eventKeyUp, &delim, "keyUp");
1867 printBitMasked(&event2, eventData, &delim, "data");
1868 printBitMasked(&event2, eventInitialize, &delim, "initialize");
1869 printBitMasked(&event2, eventConstruct, &delim, "construct");
1870 printBitMasked(&event2, eventPress, &delim, "press");
1871 printBitMasked(&event2, eventRelease, &delim, "release");
1872 printBitMasked(&event2, eventReleaseOutside, &delim, "releaseOutside");
1873 printBitMasked(&event2, eventRollOver, &delim, "rollOver");
1874 printBitMasked(&event2, eventRollOut, &delim, "rollOut");
1875 printBitMasked(&event2, eventDragOver, &delim, "dragOver");
1876 printBitMasked(&event2, eventDragOut, &delim, "dragOut");
1877
1878 if (printBitMasked(&event2, eventKeyPress, &delim, "")) {
1879 key = (byte) fgetc(f);
1880 parseKeyPressEvent(key);
1881 length--;
1882 delim = ',';
1883 }
1884
1885 if (event2 != 0) {
1886 printf("%c%lu // unknown event", delim, event2);
1887 tellUser(0, "Unknown event: %lu", event2);
1888 }
1889 printf("\n");
1890 printActionBlock(f, length, AB_MCEVENT, event, key);
1891 print("end\n");
1892 --indent;
1893 }
1894
parsePlaceObject(FILE * f,unsigned long int length,unsigned int type)1895 static void parsePlaceObject(FILE *f, unsigned long int length, unsigned int type)
1896 {
1897 int i;
1898 unsigned int flags;
1899 unsigned int clipID = 0;
1900 unsigned int depth;
1901 unsigned long int curEvent;
1902
1903 if (type == TAG_PLACEOBJECT2)
1904 flags = fgetc(f);
1905 else
1906 flags = getWord(f);
1907
1908 if (flags & PF_ONCLIPEVENTS) {
1909 printf("\n");
1910
1911 /* character depth */
1912 depth = getWord(f);
1913
1914 /* clipID should always be present */
1915 if (flags & PF_CHARACTER) {
1916 print("placeMovieClip %u ", clipID = getWord(f));
1917 }
1918 else {
1919 print("placeMovieClip ??? ");
1920 tellUser(0, "placeMovieClip: clip ID not found");
1921 }
1922
1923 if (flags & PF_MATRIX)
1924 skipMatrix(f);
1925 if (flags & PF_COLORTRANSFORM)
1926 skipColorTransform(f);
1927 if (flags & PF_RATIO)
1928 getWord(f);
1929
1930 if (flags & PF_NAME) {
1931 printf("as ");
1932 putchar('\'');
1933 while ((i = fgetc(f)) != 0)
1934 putchar((char) i);
1935 putchar('\'');
1936 }
1937
1938 if (flags & PF_DEFINECLIP)
1939 getWord(f);
1940
1941 if (type == TAG_PLACEOBJECT3) {
1942 if (flags & PF_FILTERS)
1943 skipFilters(f, (byte) fgetc(f));
1944 if (flags & PF_BLENDMODE)
1945 fgetc(f);
1946 if (flags & PF_BITMAPCACHING)
1947 fgetc(f);
1948 }
1949
1950 printf("\n");
1951
1952
1953 /* reserved: always 0 */
1954 getWord(f);
1955
1956 if (swfVersion >= 6 || type == TAG_PLACEOBJECT3) {
1957 /* flash 6 supports button events for mcs, therefore going long here */
1958 getDoubleWord(f);
1959
1960 while ((curEvent = getDoubleWord(f)) != 0)
1961 parseEvent(f, curEvent, getDoubleWord(f));
1962 }
1963 else {
1964 /* all events */
1965 getWord(f);
1966 while ((curEvent = (unsigned long int) getWord(f)) != 0)
1967 parseEvent(f, curEvent, getDoubleWord(f));
1968 }
1969
1970 if (flags & PF_CHARACTER)
1971 print("end // of placeMovieClip %u\n", clipID);
1972 else
1973 print("end // of placeMovieClip ???\n");
1974
1975 }
1976 else {
1977 /* no events found, skip the rest of placeObject2/3 */
1978 if (type == TAG_PLACEOBJECT3)
1979 skipProtected(f, length - 2);
1980 else
1981 skipProtected(f, length - 1);
1982 }
1983 }
1984
parseMovieClip(FILE * f)1985 static void parseMovieClip(FILE *f)
1986 {
1987 unsigned int clipID, frameNum = 0, framesTotal = 0;
1988
1989 clipID = getWord(f);
1990 framesTotal = getWord(f);
1991
1992 printf("\n");
1993 print("defineMovieClip %u // total frames: %u\n", clipID, framesTotal);
1994 indent++;
1995
1996 while (!feof(f)) {
1997 unsigned int type;
1998 unsigned long int length;
1999
2000 parseTagHeader(f, &type, &length);
2001
2002 if (type == 0)
2003 break;
2004
2005 switch (type) {
2006 case TAG_DOACTION:
2007 printFrameNum(frameNum);
2008 printActionBlock(f, length, AB_FRAME, frameNum, 0);
2009 print("end // of frame %u\n", frameNum);
2010 break;
2011
2012 case TAG_PLACEOBJECT2:
2013 /* possibly onClipEvents inside */
2014 parsePlaceObject(f, length, TAG_PLACEOBJECT2);
2015 break;
2016
2017 case TAG_PLACEOBJECT3:
2018 /* possibly onClipEvents inside */
2019 parsePlaceObject(f, length, TAG_PLACEOBJECT3);
2020 break;
2021
2022 case TAG_SHOWFRAME:
2023 ++frameNum;
2024 break;
2025
2026 default:
2027 if (getTagString(type) == NULL) {
2028 print("\n");
2029 print("// unknown tag %lu length %li\n\n", type, length);
2030 }
2031 skipProtected(f, length);
2032 }
2033 }
2034
2035 --indent;
2036 print("end // of defineMovieClip %u\n", clipID);
2037 }
2038
disassembleSWF(FILE * f,char * fname)2039 void disassembleSWF(FILE *f, char *fname)
2040 {
2041 unsigned int componentID, frameNum = 0, framesTotal = 0, bits;
2042 unsigned long int i, size;
2043 float frameRate, movieWidth, movieHeight;
2044
2045 swfVersion = fgetc(f);
2046 size = getDoubleWord(f);
2047
2048 /* movie bounds */
2049 InitBits(f);
2050 bits = getBits(f, 5);
2051 /* xMin - always 0 */
2052 getBits(f, bits);
2053 /* xMax */
2054 movieWidth = ((float) getBits(f, bits)) / 20;
2055 /* yMin - always 0 */
2056 getBits(f, bits);
2057 /* yMax */
2058 movieHeight = ((float) getBits(f, bits)) / 20;
2059
2060 frameRate = ((float) fgetc(f)) / 256;
2061 frameRate += (float) fgetc(f);
2062
2063 framesTotal = getWord(f);
2064
2065 printf("movie '%s'", fname);
2066
2067 if (wasCompressed)
2068 printf(" compressed");
2069 printf(" // flash %i, total frames: %u, frame rate: ", swfVersion, framesTotal);
2070 printFloat(frameRate, 1);
2071 printf(" fps, ");
2072 printFloat(movieWidth, 1);
2073 putchar('x');
2074 printFloat(movieHeight, 1);
2075 printf(" px\n");
2076
2077 while (!feof(f)) {
2078 unsigned int type;
2079 unsigned long int length;
2080
2081 parseTagHeader(f, &type, &length);
2082
2083 if (type == 0)
2084 break;
2085
2086 switch (type) {
2087 case TAG_DOACTION:
2088 printFrameNum(frameNum);
2089 printActionBlock(f, length, AB_FRAME, frameNum, 0);
2090 print("end // of frame %u\n", frameNum);
2091 break;
2092
2093 case TAG_INITMOVIECLIP:
2094 print("\n");
2095 componentID = getWord(f);
2096 print("initMovieClip %i\n", componentID);
2097 printActionBlock(f, length - 2, AB_INITMC, componentID, 0);
2098 print("end // of initMovieClip %i\n", componentID);
2099 break;
2100
2101 case TAG_PLACEOBJECT2:
2102 /* possibly onClipEvents inside */
2103 parsePlaceObject(f, length, TAG_PLACEOBJECT2);
2104 break;
2105
2106 case TAG_PLACEOBJECT3:
2107 /* possibly onClipEvents inside */
2108 parsePlaceObject(f, length, TAG_PLACEOBJECT3);
2109 break;
2110
2111 case TAG_DEFINEBUTTON2:
2112 /* possibly button events inside */
2113 parseButton2(f, length);
2114 break;
2115
2116 case TAG_SHOWFRAME:
2117 ++frameNum;
2118 break;
2119
2120 case TAG_SCRIPTLIMITS: {
2121 unsigned int recursion = getWord(f);
2122 unsigned int timeout = getWord(f);
2123 print("\n");
2124 print("scriptLimits recursion %u timeout %u\n", recursion, timeout);
2125 break;
2126 }
2127
2128 case TAG_PROTECT:
2129 print("\n");
2130 print("protect");
2131 if (length > 0) {
2132 /* password found */
2133 printf(" '");
2134 /* always 0 */
2135 getWord(f);
2136 for (i = 2; i < length - 1; ++i) {
2137 putchar((char) fgetc(f));
2138 }
2139 /* always 0 - string end */
2140 fgetc(f);
2141 putchar('\'');
2142 }
2143 putchar('\n');
2144 break;
2145
2146 case TAG_ENABLEDEBUGGER:
2147 print("\n");
2148 print("enableDebugger");
2149 if (length > 0) {
2150 /* password found */
2151 /* debugger always uses password, even for empty one */
2152 printf(" '");
2153 /* always 0 */
2154 getWord(f);
2155 for (i = 2; i < length - 1; ++i) {
2156 putchar((char) fgetc(f));
2157 }
2158 /* always 0 - string end */
2159 fgetc(f);
2160 putchar('\'');
2161 }
2162 putchar('\n');
2163 break;
2164
2165 case TAG_ENABLEDEBUGGER2:
2166 /* flash MX debugger */
2167 print("\n");
2168 print("enableDebugger2");
2169 if (length > 0) {
2170 /* password found */
2171 /* debugger always uses password, even for empty one */
2172 printf(" '");
2173 /* reserved, always 0 */
2174 getWord(f);
2175 for (i = 2; i < length - 1; ++i) {
2176 putchar((char) fgetc(f));
2177 }
2178 /* always 0 - string end */
2179 fgetc(f);
2180 putchar('\'');
2181 }
2182 putchar('\n');
2183 break;
2184
2185 case TAG_DEFINEMOVIECLIP:
2186 parseMovieClip(f);
2187 break;
2188
2189 case TAG_EXPORTASSETS: {
2190 unsigned int assetID, numAssets = getWord(f);
2191 int n;
2192 print("\n");
2193 print("exportAssets\n");
2194 ++indent;
2195 while (numAssets--) {
2196 print("%u as '", assetID = getWord(f));
2197 while ((n = fgetc(f)) != 0) {
2198 putchar((char) n);
2199 }
2200 printf("'\n");
2201 }
2202 --indent;
2203 print("end // of exportAssets\n");
2204 break;
2205 }
2206
2207 case TAG_IMPORTASSETS:
2208 case TAG_IMPORTASSETS2: {
2209 unsigned int assetID, numAssets, attr;
2210 int n;
2211 print("\n");
2212 print("importAssets from '");
2213 while ((n = fgetc(f)) != 0) {
2214 putchar((char) n);
2215 }
2216 printf("'\n");
2217 if (type == TAG_IMPORTASSETS2) {
2218 /* Reserved: always 1 */
2219 attr = getWord(f);
2220 if (attr != 1)
2221 tellUser(0, "Unknown importAssets2 attribute: %u (should be 1)", attr);
2222 }
2223 numAssets = getWord(f);
2224 ++indent;
2225 while (numAssets--) {
2226 assetID = getWord(f);
2227 print("'");
2228 while ((n = fgetc(f)) != 0) {
2229 putchar((char) n);
2230 }
2231 printf("' as %u\n", assetID);
2232 }
2233 --indent;
2234 print("end // of importAssets\n");
2235 break;
2236 }
2237
2238 case TAG_METADATA: {
2239 static char buf[MAX_BUFFER];
2240 print("\n");
2241 print("metadata ");
2242 fread(buf, 1, length, f);
2243 printstr(buf);
2244 putchar('\n');
2245 break;
2246 }
2247
2248 case TAG_FILEATTRIBUTES: {
2249 char delim = ' ';
2250 unsigned long int attrs = getDoubleWord(f);
2251 if (attrs) {
2252 print("\n");
2253 print("fileAttributes");
2254 }
2255 printBitMasked(&attrs, ATTR_USENETWORK, &delim, "attrUseNetwork");
2256 printBitMasked(&attrs, ATTR_RELATIVEURLS, &delim, "attrRelativeURLs");
2257 printBitMasked(&attrs, ATTR_SUPPRESSCROSSDOMAINCACHE, &delim, "attrSuppressCrossDomainCache");
2258 printBitMasked(&attrs, ATTR_ACTIONSCRIPT3, &delim, "attrActionScript3");
2259 printBitMasked(&attrs, ATTR_HASMETADATA, &delim, "attrHasMetadata");
2260 if (attrs != 0) {
2261 printf("%c%lu // unknown attribute", delim, attrs);
2262 tellUser(0, "Unknown file attribute: %lu", attrs);
2263 }
2264 printf("\n");
2265 break;
2266 }
2267
2268 default:
2269 if (getTagString(type) == NULL) {
2270 print("\n");
2271 print("// unknown tag %lu length %li\n", type, length);
2272 }
2273 skipProtected(f, length);
2274 }
2275 }
2276
2277 fclose(f);
2278 printf("end\n");
2279 }
2280