ntype.club

hollywood

a year later, I finish micro

So it’s a VM with a nasty unpacker. Stepping through the code it becomes obvious that a few instructions are decrypted to 0xeXXX jumped to and then branched back to the unpacker to decrypt the next set of instructions.

Using I modified the source to dump instructions that occur after 0xe000. Using the provided disassembler with my generated trace and filtering all the extraneous instructions, the following lines are decoded.

clr r6    
          
# This loops until input is terminated with \x00
{
add @r5, r4 
swpb r4   
xor @r5+, r6
xor r4, r6
xor r6, r4 
xor r4, r6
tst 0x00(r5)
mov sr, r7
and 0x2, r7
rra r7
xor 0x1, r7   
swpb r7   
rra r7      
sxt r7        
swpb r7   
sxt r7
mov 0x4b18, r8 
and r7, r8 
xor -0x1, r7
and 0x47aa, r7                                               
add r7, r8                                     
clr r7                
}
                                                    
mov r8, r12               
cmp 0xfeb1, r4            
mov sr, r7                                  
clr r4
cmp 0x9298, r6                                                         
and sr, r7                                                           
clr r6                                                        
rra r7                                    
xor 1, r7                                                
swpb r7                                           
rra r7        
rra r7                                      
rra r7                    
rra r7        
bis r7, sr

Right so the r7, r8 shuffle is actually thrown out, the trick here is that if r4 and r6 do not equal 0xFEB1 and 0x9298 the rotate instructions set the CPUOFF flag on the status register killing the machine. So brute-forcing the r4, r6 registers we can get the password. I wrote the solver in C since my python script took a million years versus a few seconds, the below will output all 6-byte solutions. I tried 4-byte initially but the solution space is a null-set.

#include <stdio.h>
#define SWP(a) ((a & 0xFF00) >> 8 | (a & 0xFF) << 8) 
                                                              
int main()                                                
{                                                         
    unsigned int last;                  
    unsigned int ii, jj;                
    unsigned int r4 = 0;                
    unsigned int r6 = 0;                
                                
    for(ii = 1; ii < 0x10000; ii++) {
        for(jj = 1; jj < 0x10000; jj++) {
            r6 = ((ii&0xFF00) >> 8) | ((ii & 0xFF) << 8);  
            r4 = ii;                                       
            r4 = (r4 + jj) & 0xFFFF;
            r4 = ((r4 & 0xFF00) >> 8) | ((r4 & 0xFF) << 8);
            r6 ^= jj;    
                                
            r6 ^= r4;     
            r4 ^= r6;            
            r6 ^= r4;                        
                                                               
            last = (r6 ^ 0xfeb1);
            if(((last+r4) & 0xFFFF) == 0x9892) {
                printf("SOL %04X %04X %04X\r\n", SWP(ii), SWP(jj), SWP(last));
            }                                                    
        }    
    }                                                          
    
    return 1;
}