| /* |
| * Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/ |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| * MA 02110-1301, USA. |
| */ |
| |
| /* |
| * upack.c |
| * |
| * |
| */ |
| |
| #if HAVE_CONFIG_H |
| #include "clamav-config.h" |
| #endif |
| |
| #include <stdio.h> |
| #ifdef HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #ifdef HAVE_SYS_TYPES_H |
| #include <sys/types.h> |
| #endif |
| #ifdef HAVE_SYS_STAT_H |
| #include <sys/stat.h> |
| #endif |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #endif |
| |
| #include "cltypes.h" |
| #include "pe.h" |
| #include "rebuildpe.h" |
| #include "others.h" |
| #include "upack.h" |
| #include "mew.h" |
| |
| #define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
| #define CE32(x) be32_to_host(x) /* Convert big endian to host */ |
| |
| int unupack399(char *, uint32_t, uint32_t, char *, uint32_t, char *, char *, uint32_t, char *); |
| |
| enum { UPACK_399, UPACK_11_12, UPACK_0151477, UPACK_0297729 }; |
| |
| int unupack(int upack, char *dest, uint32_t dsize, char *buff, uint32_t vma, uint32_t ep, uint32_t base, uint32_t va, int file) |
| { |
| int j, searchval; |
| char *loc_esi, *loc_edi, *loc_ebx, *end_edi, *save_edi, *rpeb, *alvalue; |
| char *paddr, *pushed_esi, *save2; |
| uint32_t save1, save3, loc_ecx, count, shlsize, original_ep, ret, loc_ebx_u; |
| struct cli_exe_section section; |
| int upack_version = UPACK_399; |
| |
| /* buff [168 bytes] doesn't have to be checked, since it was checked in pe.c */ |
| if (upack) |
| { |
| uint32_t aljump, shroff, lngjmpoff; |
| |
| /* dummy characteristics ;/ */ |
| if (buff[5] == '\xff' && buff[6] == '\x36') |
| upack_version = UPACK_0297729; |
| loc_esi = dest + (cli_readint32(buff + 1) - vma); |
| |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12)) |
| return -1; |
| original_ep = cli_readint32(loc_esi); |
| loc_esi += 4; |
| /*cli_readint32(loc_esi);*/ |
| loc_esi += 4; |
| |
| original_ep -= vma; |
| cli_dbgmsg("Upack: EP: %08x original: %08X || %08x\n", ep, original_ep, cli_readint32(loc_esi-8)); |
| |
| if (upack_version == UPACK_399) |
| { |
| /* jmp 1 */ |
| loc_edi = dest + (cli_readint32(loc_esi) - vma); |
| if (!CLI_ISCONTAINED(dest, dsize, dest+ep+0xa, 2) || dest[ep+0xa] != '\xeb') |
| return -1; |
| loc_esi = dest + *(dest + ep + 0xb) + ep + 0xc; |
| |
| /* use this as a temp var */ |
| /* jmp 2 + 0xa */ |
| alvalue = loc_esi+0x1a; |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xeb') |
| return -1; |
| alvalue++; |
| alvalue += (*alvalue&0xff) + 1 + 0xa; |
| lngjmpoff = 8; |
| } else { |
| if (!CLI_ISCONTAINED(dest, dsize, dest+ep+7, 5) || dest[ep+7] != '\xe9') |
| return -1; |
| loc_esi = dest + cli_readint32(dest + ep + 8) + ep + 0xc; |
| alvalue = loc_esi + 0x25; |
| lngjmpoff = 10; |
| } |
| |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xb5') |
| return -1; |
| alvalue++; |
| count = *alvalue&0xff; |
| |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue, lngjmpoff+5) || *(alvalue+lngjmpoff) != '\xe9') |
| return -1; |
| /* use this as a temp to make a long jmp to head of unpacking proc */ |
| shlsize = cli_readint32(alvalue + lngjmpoff+1); |
| /* upack_399 + upack_0151477 */ |
| if (upack_version == UPACK_399) |
| shlsize = shlsize + (loc_esi - dest) + *(loc_esi+0x1b) + 0x1c + 0x018; /* read checked above */ |
| else |
| /* there is no additional jump in upack_0297729 */ |
| shlsize = shlsize + (loc_esi - dest) + 0x035; |
| /* do the jump, 43 - point to jecxz */ |
| alvalue = dest+shlsize+43; |
| |
| /* 0.39 */ |
| aljump = 8; |
| shroff = 24; |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3') |
| { |
| /* in upack_0297729 and upack_0151477 jecxz is at offset: 46 */ |
| alvalue = dest+shlsize+46; |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3') |
| return -1; |
| else { |
| if (upack_version != UPACK_0297729) |
| upack_version = UPACK_0151477; |
| aljump = 7; |
| shroff = 26; |
| } |
| |
| } |
| /* do jecxz */ |
| alvalue += (*alvalue&0xff) + 1; |
| /* is there a long jump ? */ |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue, aljump+5) || *(alvalue+aljump) != '\xe9') |
| return -1; |
| /* do jmp, 1+4 - size of jmp instruction, aljump - instruction offset, 27 offset to cmp al,xx*/ |
| ret = cli_readint32(alvalue+aljump+1); |
| alvalue += ret + aljump+1+4 + 27; |
| if (upack_version == UPACK_0297729) |
| alvalue += 2; |
| /* shr ebp */ |
| if (!CLI_ISCONTAINED(dest, dsize, dest+shlsize+shroff, 3) || *(dest+shlsize+shroff) != '\xc1' || *(dest+shlsize+shroff+1) != '\xed') |
| return -1; |
| shlsize = (*(dest + shlsize + shroff+2))&0xff; |
| count *= 0x100; |
| if (shlsize < 2 || shlsize > 8) |
| { |
| cli_dbgmsg ("Upack: context bits out of bounds\n"); |
| return -1; |
| } |
| cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count); |
| /* check if loc_esi + .. == 0xbe -> mov esi */ |
| /* upack_0297729 has mov esi, .. + mov edi, .., in upack_0151477 and upack_399 EDI has been already set before */ |
| if (upack_version == UPACK_0297729) |
| { |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi+6, 10) || *(loc_esi+6) != '\xbe' || *(loc_esi+11) != '\xbf') |
| return -1; |
| if ((uint32_t)cli_readint32(loc_esi + 7) < base || (uint32_t)cli_readint32(loc_esi+7) > vma) |
| return -1; |
| loc_edi = dest + (cli_readint32(loc_esi + 12) - vma); |
| loc_esi = dest + (cli_readint32(loc_esi + 7) - base); |
| } else { |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi+7, 5) || *(loc_esi+7) != '\xbe') |
| return -1; |
| loc_esi = dest + (cli_readint32(loc_esi + 8) - vma); |
| } |
| |
| if (upack_version == UPACK_0297729) |
| { |
| /* 0x16*4=0x58, 6longs*4 = 24, 0x64-last loc_esi read location */ |
| if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x58 + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x58 + 0x64 + 4))) |
| return -1; |
| |
| /* XXX I don't know if this [0x16] is constant number, not enough samples provided */ |
| for (j=0; j<0x16; j++, loc_esi+=4, loc_edi+=4) |
| cli_writeint32(loc_edi, cli_readint32(loc_esi)); |
| } else { |
| /* 0x27*4=0x9c, 6longs*4 = 24, 0x34-last loc_esi read location */ |
| if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x9c + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x9c + 0x34 + 4))) |
| return -1; |
| for (j=0; j<0x27; j++, loc_esi+=4, loc_edi+=4) |
| cli_writeint32(loc_edi, cli_readint32(loc_esi)); |
| } |
| save3 = cli_readint32(loc_esi + 4); |
| paddr = dest + ((uint32_t)cli_readint32(loc_edi - 4)) - vma; |
| loc_ebx = loc_edi; |
| cli_writeint32(loc_edi, 0xffffffff); |
| loc_edi+=4; |
| cli_writeint32(loc_edi, 0); |
| loc_edi+=4; |
| for (j=0; j<4; j++, loc_edi+=4) |
| cli_writeint32(loc_edi, (1)); |
| |
| for (j=0; (unsigned int)j<count; j++, loc_edi+=4) |
| cli_writeint32(loc_edi, 0x400); |
| |
| loc_edi = dest + cli_readint32(loc_esi + 0xc) - vma; |
| if (upack_version == UPACK_0297729) |
| loc_edi = dest+vma-base; /* XXX not enough samples provided to be sure of it! */ |
| |
| pushed_esi = loc_edi; |
| end_edi = dest + cli_readint32(loc_esi + 0x34) - vma; |
| if (upack_version == UPACK_0297729) |
| { |
| end_edi = dest + cli_readint32(loc_esi + 0x64) - vma; |
| save3 = cli_readint32(loc_esi + 0x40); |
| } |
| /* begin end */ |
| cli_dbgmsg("Upack: data initialized, before upack lzma call!\n"); |
| if ((ret = (uint32_t)unupack399(dest, dsize, 0, loc_ebx, 0, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff) |
| return -1; |
| /* alternative begin */ |
| } else { |
| int ep_jmp_offs, rep_stosd_count_offs, context_bits_offs; |
| loc_esi = dest + vma + ep; |
| /* yet another dummy characteristics ;/ */ |
| if (buff[0] == '\xbe' && buff[5] == '\xad' && buff[6] == '\x8b' && buff[7] == '\xf8') |
| upack_version = UPACK_11_12; |
| |
| if (upack_version == UPACK_11_12) |
| { |
| ep_jmp_offs = 0x1a4; |
| rep_stosd_count_offs = 0x1b; |
| context_bits_offs = 0x41; |
| alvalue = loc_esi + 0x184; |
| } else { |
| ep_jmp_offs = 0x217; |
| rep_stosd_count_offs = 0x3a; |
| context_bits_offs = 0x5f; |
| alvalue = loc_esi + 0x1c1; |
| } |
| |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi, ep_jmp_offs+4)) |
| return -1; |
| save1 = cli_readint32(loc_esi + ep_jmp_offs); |
| original_ep = (loc_esi - dest) + ep_jmp_offs + 4; |
| original_ep += (int32_t)save1; |
| cli_dbgmsg("Upack: EP: %08x original %08x\n", ep, original_ep); |
| |
| /* this are really ugly hacks, |
| * rep_stosd_count_offs & context_bits_offs are < ep_jmp_offs, |
| * so checked in CLI_ISCONTAINED above */ |
| count = (*(loc_esi + rep_stosd_count_offs))&0xff; |
| shlsize = (*(loc_esi + context_bits_offs))&0xff; |
| shlsize = 8 - shlsize; |
| if (shlsize < 2 || shlsize > 8) |
| { |
| cli_dbgmsg ("Upack: context bits out of bounds\n"); |
| return -1; |
| } |
| count *= 0x100; |
| cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count); |
| if (upack_version == UPACK_399) |
| { |
| loc_esi += 4; |
| loc_ecx = cli_readint32(loc_esi+2); |
| cli_writeint32(loc_esi+2,0); |
| if (!loc_ecx) |
| { |
| cli_dbgmsg("Upack: something's wrong, report back\n"); |
| return -1;/* XXX XXX XXX XXX */ |
| } |
| loc_esi -= (loc_ecx - 2); |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12)) |
| return -1; |
| |
| cli_dbgmsg("Upack: %08x %08x %08x %08x\n", loc_esi, dest, cli_readint32(loc_esi), base); |
| loc_ebx_u = loc_esi - (dest + cli_readint32(loc_esi) - base); |
| cli_dbgmsg("Upack: EBX: %08x\n", loc_ebx_u); |
| loc_esi += 4; |
| save2 = loc_edi = dest + cli_readint32(loc_esi) - base; |
| cli_dbgmsg("Upack: DEST: %08x, %08x\n", cli_readint32(loc_esi), cli_readint32(loc_esi) - base); |
| loc_esi += 4; |
| /* 2vGiM: j is signed. Is that really what you want? Will it cause problems with the following checks? |
| * yes! this is wrong! how did you notice that?! |
| */ |
| j = cli_readint32(loc_esi); |
| if (j<0) |
| { |
| cli_dbgmsg("Upack: probably hand-crafted data, report back\n"); |
| return -1; |
| } |
| loc_esi += 4; |
| cli_dbgmsg("Upack: ecx counter: %08x\n", j); |
| |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi, (j*4)) || !CLI_ISCONTAINED(dest, dsize, loc_edi, ((j+count)*4))) |
| return -1; |
| for (;j--; loc_edi+=4, loc_esi+=4) |
| cli_writeint32(loc_edi, cli_readint32(loc_esi)); |
| if (!CLI_ISCONTAINED(dest, dsize, save2, 8)) |
| return -1; |
| loc_ecx = cli_readint32(save2); |
| save2 += 4; |
| loc_esi = save2; |
| /* I could probably do simple loc_esi+= (0xe<<2), |
| * but I'm not sure if there is always 0xe and is always ebx =0 |
| */ |
| do { |
| loc_esi += loc_ebx_u; |
| loc_esi += 4; |
| } while (--loc_ecx); |
| if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 4)) |
| return -1; |
| save1 = cli_readint32(loc_esi); /* loc_eax = 0x400 */ |
| loc_esi += 4; |
| |
| for (j=0; j<count; j++, loc_edi+=4) /* checked above */ |
| cli_writeint32(loc_edi, (save1)); |
| |
| if (!CLI_ISCONTAINED(dest, dsize, (loc_esi+0x10), 4)) |
| return -1; |
| cli_writeint32(loc_esi+0x10, (uint32_t)cli_readint32(loc_esi+0x10)+loc_ebx_u); |
| loc_ebx = loc_esi+0x14; |
| loc_esi = save2; |
| /* loc_ebx_u gets saved */ |
| /* checked above, (...save2, 8) */ |
| save_edi = loc_edi = dest + ((uint32_t)cli_readint32(loc_esi) - base); |
| loc_esi +=4; |
| cli_dbgmsg("Upack: before_fixing\n"); |
| /* fix values */ |
| if (!CLI_ISCONTAINED(dest, dsize, loc_ebx-4, (12 + 4*4)) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x24, 4) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x40, 4)) |
| return -1; |
| for (j=2; j<6; j++) |
| cli_writeint32(loc_ebx+(j<<2), cli_readint32(loc_ebx+(j<<2))); |
| paddr = dest + cli_readint32(loc_ebx - 4) - base; |
| save1 = loc_ecx; |
| pushed_esi = loc_edi; |
| end_edi = dest + cli_readint32(loc_esi+0x24) - base; |
| vma = cli_readint32(loc_ebx); cli_writeint32(loc_ebx, cli_readint32(loc_ebx + 4)); cli_writeint32((loc_ebx + 4), vma); |
| /* Upack 1.1/1.2 is something between 0.39 2-section and 0.39 3-section */ |
| } else if (upack_version == UPACK_11_12) { |
| cli_dbgmsg("Upack v 1.1/1.2\n"); |
| loc_esi = dest + 0x148; /* always constant? */ |
| loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */ |
| loc_esi += 4; |
| save_edi = loc_edi; |
| /* movsd */ |
| paddr = dest + ((uint32_t)cli_readint32(loc_esi)) - base; |
| loc_esi += 4; |
| loc_edi += 4; |
| loc_ebx = loc_edi; |
| |
| if (!CLI_ISCONTAINED(dest, dsize, loc_edi, ((6+count)*4))) |
| return -1; |
| cli_writeint32(loc_edi, 0xffffffff); |
| loc_edi += 4; |
| cli_writeint32(loc_edi, 0); |
| loc_edi += 4; |
| for (j=0; j<4; j++, loc_edi+=4) |
| cli_writeint32(loc_edi, (1)); |
| |
| for (j=0; j<count; j++, loc_edi+=4) |
| cli_writeint32(loc_edi, 0x400); |
| |
| loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */ |
| pushed_esi = loc_edi; |
| loc_esi += 4; |
| loc_ecx = 0; |
| |
| loc_esi += 4; |
| |
| end_edi = dest + cli_readint32(loc_esi-0x28) - base; /* read checked above */ |
| loc_esi = save_edi; |
| } |
| cli_dbgmsg("Upack: data initialized, before upack lzma call!\n"); |
| if ((ret = (uint32_t)unupack399(dest, dsize, loc_ecx, loc_ebx, loc_ecx, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff) |
| return -1; |
| if (upack_version == UPACK_399) |
| save3 = cli_readint32(loc_esi + 0x40); |
| else if (upack_version == UPACK_11_12) |
| save3 = cli_readint32(dest + vma + ep + 0x174); |
| } |
| |
| /* let's fix calls */ |
| loc_ecx = 0; |
| if (!CLI_ISCONTAINED(dest, dsize, alvalue, 1)) { |
| cli_dbgmsg("Upack: alvalue out of bounds\n"); |
| return -1; |
| } |
| |
| searchval = *alvalue&0xff; |
| cli_dbgmsg("Upack: loops: %08x search value: %02x\n", save3, searchval); |
| while(save3) { |
| if (!CLI_ISCONTAINED(dest, dsize, pushed_esi + loc_ecx, 1)) |
| { |
| cli_dbgmsg("Upack: callfixerr %08x %08x = %08x, %08x\n", dest, dsize, dest+dsize, pushed_esi+loc_ecx); |
| return -1; |
| } |
| if (pushed_esi[loc_ecx] == '\xe8' || pushed_esi[loc_ecx] == '\xe9') |
| { |
| char *adr = (pushed_esi + loc_ecx + 1); |
| loc_ecx++; |
| if (!CLI_ISCONTAINED(dest, dsize, adr, 4)) |
| { |
| cli_dbgmsg("Upack: callfixerr\n"); |
| return -1; |
| } |
| if ((cli_readint32(adr)&0xff) != searchval) |
| continue; |
| cli_writeint32(adr, EC32(CE32((uint32_t)(cli_readint32(adr)&0xffffff00)))-loc_ecx-4); |
| loc_ecx += 4; |
| save3--; |
| } else |
| loc_ecx++; |
| } |
| |
| section.raw = 0; |
| section.rva = va; |
| section.rsz = end_edi-loc_edi; |
| section.vsz = end_edi-loc_edi; |
| |
| if (!cli_rebuildpe(dest + (upack?0:va), §ion, 1, base, original_ep, 0, 0, file)) { |
| cli_dbgmsg("Upack: Rebuilding failed\n"); |
| return 0; |
| } |
| return 1; |
| } |
| |
| |
| int unupack399(char *bs, uint32_t bl, uint32_t init_eax, char *init_ebx, uint32_t init_ecx, char *init_edi, char *end_edi, uint32_t shlsize, char *paddr) |
| { |
| struct lzmastate p; |
| uint32_t loc_eax, ret, loc_al, loc_ecx = init_ecx, loc_ebp, eax_copy = init_eax, temp, i, jakas_kopia; |
| uint32_t state[6], temp_ebp; |
| char *loc_edx, *loc_ebx = init_ebx, *loc_edi = init_edi, *loc_ebp8, *edi_copy; |
| p.p0 = paddr; |
| p.p1 = cli_readint32(init_ebx); |
| p.p2 = cli_readint32(init_ebx + 4); |
| |
| cli_dbgmsg("\n\tp0: %08x\n\tp1: %08x\n\tp2: %08x\n", p.p0, p.p1, p.p2); |
| for (i = 0; i<6; i++) |
| state[i] = cli_readint32(loc_ebx + (i<<2)), |
| cli_dbgmsg("state[%d] = %08x\n", i, state[i]); |
| do { |
| loc_eax = eax_copy; |
| loc_edx = loc_ebx + (loc_eax<<2) + 0x58; |
| |
| if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) |
| { |
| /* loc_483927 */ |
| loc_al = loc_eax&0xff; |
| loc_al = ((loc_al + 0xf9) > 0xff)?(3+8):8; |
| loc_eax = (loc_eax&0xffffff00)|(loc_al&0xff); |
| loc_ebp = state[2]; |
| loc_ecx = (loc_ecx&0xffffff00)|0x30; |
| loc_edx += loc_ecx; |
| /* *(uint32_t *)(loc_ebx + 14) = loc_ebp; ???? */ |
| if (!(ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) { |
| /* loc_48397c */ |
| loc_eax--; |
| /* |
| temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x0c); cli_writeint32(loc_ebx+0x0c, temp_ebp); |
| temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x10); cli_writeint32(loc_ebx+0x10, temp_ebp); |
| */ |
| temp_ebp = loc_ebp; |
| loc_ebp = state[4]; |
| state[4] = state[3]; |
| state[3] = temp_ebp; |
| eax_copy = loc_eax; |
| loc_edx = loc_ebx + 0xbc0; |
| state[5] = loc_ebp; |
| if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff) |
| return -1; |
| loc_ecx = 3; |
| jakas_kopia = temp; |
| loc_eax = temp-1; |
| if (loc_eax >= loc_ecx) |
| loc_eax = loc_ecx; |
| loc_ecx = 0x40; |
| loc_eax <<= 6; /* ecx=0x40, mul cl */ |
| loc_ebp8 = loc_ebx + ((loc_eax<<2) + 0x378); |
| if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff) |
| return -1; |
| loc_ebp = loc_eax; |
| if ((loc_eax&0xff) >= 4) |
| { |
| /* loc_4839af */ |
| loc_ebp = 2 + (loc_eax&1); |
| loc_eax >>= 1; |
| loc_eax--; |
| temp_ebp = loc_eax; loc_eax = loc_ecx; loc_ecx = temp_ebp; |
| loc_ebp <<= (loc_ecx&0xff); |
| loc_edx = loc_ebx + (loc_ebp<<2) + 0x178; |
| if ((loc_ecx&0xff) > 5) |
| { |
| /* loc_4839c6 */ |
| loc_ecx = (loc_ecx&0xffffff00)|(((loc_ecx&0xff)-4)&0xff); |
| loc_eax = 0; |
| do { |
| uint32_t temp_edx; |
| /* compare with lzma_upack_esi_00 */ |
| /* do not put in one statment because of difference in signedness */ |
| if (!CLI_ISCONTAINED(bs, bl, p.p0, 4)) |
| return -1; |
| temp_edx = cli_readint32((char *)p.p0); |
| temp_edx = EC32(CE32(temp_edx)); |
| p.p1 >>= 1; |
| temp_edx -= p.p2; |
| loc_eax <<= 1; |
| if (temp_edx >= p.p1) |
| { |
| temp_edx = p.p1; |
| loc_eax++; |
| p.p2 += temp_edx; |
| } |
| if(((p.p1)&0xff000000) == 0) |
| { |
| p.p2 <<= 8; |
| p.p1 <<= 8; |
| p.p0++; |
| } |
| } while (--loc_ecx); |
| /* loc_4839e8 */ |
| loc_ecx = (loc_ecx&0xffffff00)|4; |
| loc_eax <<= 4; |
| loc_ebp += loc_eax; |
| loc_edx = loc_ebx + 0x18; |
| } |
| /* loc4839f1 */ |
| loc_eax = 1; |
| loc_eax <<= (loc_ecx&0xff); |
| loc_ebp8 = loc_edx; |
| temp_ebp = loc_ecx; loc_ecx = loc_eax; loc_eax = temp_ebp; |
| if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff) |
| return -1; |
| /* cdq, loc_edx = (loc_eax&0x80000000)?0xffffffff:0; */ |
| loc_ecx = temp_ebp; |
| temp_ebp = CLI_SRS((int32_t)loc_eax, 31); /* thx, desp */ |
| /* loc_483a00 */ |
| do { |
| temp_ebp += temp_ebp; |
| temp_ebp += (loc_eax&1); |
| loc_eax >>= 1; |
| } while (--loc_ecx); |
| loc_ebp += temp_ebp; |
| /* loc_483a06 */ |
| } |
| /* loc_483a09 */ |
| loc_ebp++; |
| loc_ecx = jakas_kopia; |
| } else { |
| /* loc_48393a */ |
| loc_edx += loc_ecx; |
| if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) { |
| /* loc_483954 */ |
| loc_edx += 0x60; |
| if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) { |
| /* loc_48395e */ |
| loc_edx += loc_ecx; |
| ret = lzma_upack_esi_00(&p, loc_edx, bs, bl); |
| temp_ebp = loc_ebp; |
| loc_ebp = state[4]; |
| state[4] = state[3]; |
| state[3] = temp_ebp; |
| if (ret) |
| { |
| temp_ebp = loc_ebp; loc_ebp = state[5]; state[5] = temp_ebp; |
| } |
| } else { |
| temp_ebp = loc_ebp; loc_ebp = state[3]; state[3] = temp_ebp; |
| } |
| } else { |
| /* loc_483940 */ |
| loc_edx += loc_ecx; |
| if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) { |
| } else { |
| /* loc_483946 */ |
| loc_eax |= 1; |
| eax_copy = loc_eax; |
| edi_copy = loc_edi; |
| edi_copy -= state[2]; |
| loc_ecx = (loc_ecx&0xffffff00)|0x80; |
| if (!CLI_ISCONTAINED(bs, bl, edi_copy, 1) || !CLI_ISCONTAINED(bs, bl, loc_edi, 1)) |
| return -1; |
| loc_al = (*(uint8_t *)edi_copy)&0xff; |
| /* loc_483922 */ |
| /* ok jmp to 483a19 */ |
| /* loc_483a19 */ |
| *loc_edi++ = loc_al; |
| continue; |
| } |
| } |
| /* loc_48396a */ |
| eax_copy = loc_eax; |
| loc_edx = loc_ebx + 0x778; |
| if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff) |
| return -1; |
| loc_eax = loc_ecx; |
| loc_ecx = temp; |
| } |
| /* loc_483a0b */ |
| if (!CLI_ISCONTAINED(bs, bl, loc_edi, loc_ecx) || !CLI_ISCONTAINED(bs, bl, loc_edi-loc_ebp, loc_ecx+1)) |
| return -1; |
| state[2] = loc_ebp; |
| for (i=0; i<loc_ecx; i++, loc_edi++) |
| *loc_edi = *(loc_edi - loc_ebp); |
| loc_eax = (loc_eax&0xffffff00)|*(uint8_t *)(loc_edi - loc_ebp); |
| loc_ecx = 0x80; |
| } else { |
| /* loc_4838d8 */ |
| do { |
| if ( (loc_al = (loc_eax&0xff)) + 0xfd > 0xff) |
| loc_al -= 3; /* 0x100 - 0xfd = 3 */ |
| else |
| loc_al = 0; |
| loc_eax = (loc_eax&0xffffff00)|loc_al; |
| } while (loc_al >= 7); |
| /* loc_4838e2 */ |
| eax_copy = loc_eax; |
| if (loc_edi > init_edi && loc_edi < bl+bs) |
| { |
| loc_ebp = (*(uint8_t *)(loc_edi - 1)) >> shlsize; |
| } else { |
| loc_ebp = 0; |
| } |
| loc_ebp *= (int)0x300; /* XXX */ |
| loc_ebp8 = loc_ebx + ((loc_ebp<<2) + 0x1008); |
| /* XXX save edi */ |
| edi_copy = loc_edi; |
| |
| loc_eax = (loc_eax&0xffffff00)|1; |
| if (loc_ecx) { |
| uint8_t loc_cl = loc_ecx&0xff; |
| loc_edi -= state[2]; |
| if (!CLI_ISCONTAINED(bs, bl, loc_edi, 1)) |
| return -1; |
| do { |
| loc_eax = (loc_eax&0xffff00ff)|((*loc_edi & loc_cl)?0x200:0x100); |
| |
| loc_edx = loc_ebp8 + (loc_eax<<2); |
| ret = lzma_upack_esi_00(&p, loc_edx, bs, bl); |
| loc_al = loc_eax&0xff; |
| loc_al += loc_al; |
| loc_al += ret; |
| loc_al &= 0xff; |
| loc_eax = (loc_eax&0xffffff00)|loc_al; |
| loc_cl >>= 1; |
| if (loc_cl) { |
| uint8_t loc_ah = (loc_eax>>8)&0xff; |
| loc_ah -= loc_al; |
| loc_ah &= 1; |
| if (!loc_ah) |
| { |
| loc_eax = (loc_eax&0xffff0000)|(loc_ah<<8)|loc_al; |
| /* loc_483918, loc_48391a */ |
| if (lzma_upack_esi_50(&p, loc_eax, 0x100, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff) |
| return -1; |
| break; |
| } |
| } else |
| break; |
| } while(1); |
| } else { |
| /* loc_48391a */ |
| loc_ecx = (loc_ecx&0xffff00ff)|0x100; |
| if (lzma_upack_esi_50(&p, loc_eax, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff) |
| return -1; |
| } |
| /* loc_48391f */ |
| loc_ecx = 0; |
| loc_edi = edi_copy; |
| } |
| /* loc_483a19 */ |
| /* 2GiM: i think this one is not properly checked, 2aCaB: true */ |
| if (!CLI_ISCONTAINED(bs, bl, loc_edi, 1)) |
| return -1; |
| *loc_edi++ = (loc_eax&0xff); |
| } while (loc_edi < end_edi); |
| |
| return 1; |
| } |