openyou / emokit

Open source driver for accessing raw data from the Emotiv EPOC EEG headset
http://www.openyou.org
Other
521 stars 235 forks source link

Deciphering the functions. #256

Open warrenarea opened 7 years ago

warrenarea commented 7 years ago

So it occurs to me that trying to locate the get_level and decryption functions, based on where the rjindael code is... is pretty much a lost cause, because the rjindael is just mixed in with a bunch of other encryption functions, and they could be doing all sorts of other processes in between actually utilizing the data acquired.

So I think I'm getting a little closer, by first looking at "Imports" or Symbols, which are basically the function names.

What I want to focus on at this point, is "sure thing" code and recognizable code segments, because there is a ton of code, and we don't want to waste our time on false positives and confusing ourselves.

I think I'll break the code up into sections, to make it easier to edit later.

If you want to comment on an item, reference its function name. (for clarity)

warrenarea commented 7 years ago

okay, an even BETTER find. Here is the function for the Epoc+ crypt keys and their variants.

As a recap, here is the one we found the other day...

k = ['\0'] * 16
k[0] = serial_number[-1]
k[1] = '\x00'
k[2] = serial_number[-2]
k[3] = '\x15'
k[4] = serial_number[-3]
k[5] = '\x00'
k[6] = serial_number[-4]
k[7] = '\x0C'
k[8] = serial_number[-3]
k[9] = '\x00'
k[10] = serial_number[-2]
k[11] = 'D'
k[12] = serial_number[-1]
k[13] = '\x00'
k[14] = serial_number[-2]
k[15] = 'X'

Now compare it to the code here:

where D=68 X=88 and 12 = 0xC and v9/byte1/byte2/byte3 = SN

char __thiscall sub_1290AC0(int this)
{
  int v1; // edi@1
  char *v2; // ecx@1
  char *v3; // eax@3
  _BYTE *v4; // ecx@3
  _BYTE *v5; // ecx@5
  char v6; // ST20_1@7
  int v8; // [sp+Ch] [bp-4Ch]@1
  int v9; // [sp+10h] [bp-48h]@7
  void *v10; // [sp+18h] [bp-40h]@1
  int v11; // [sp+28h] [bp-30h]@3
  unsigned int v12; // [sp+2Ch] [bp-2Ch]@1
  void *v13; // [sp+30h] [bp-28h]@3
  int v14; // [sp+40h] [bp-18h]@3
  unsigned int v15; // [sp+44h] [bp-14h]@3
  int v16; // [sp+54h] [bp-4h]@3

  v8 = this;
  v1 = this + 158;
  _mm_storeu_si128((this + 158), 0i64);
  (*(*this + 48))(&v10);
  v2 = &v10;
  if ( v12 >= 8 )
  {
    v2 = v10;
  }
  v16 = 0;
  v15 = 15;
  v3 = &v2[2 * v11];
  v14 = 0;
  v4 = &v10;
  LOBYTE(v13) = 0;
  if ( v12 >= 8 )
  {
    v4 = v10;
  }
  sub_11910C0(&v13, v4, v3, v8);
  v5 = &v13;
  if ( v15 >= 0x10 )
  {
    v5 = v13;
  }
  LOBYTE(v16) = 1;
  v9 = *v5;
  v6 = v5[4];
  if ( (*(*v8 + 76))(v8) == 2 )
  {
    if ( *(v8 + 148) & 0xF00 )
    {
      *(v8 + 4) = 2;
    }
    else
    {
      *(v8 + 4) = 3;
    }
  }
  else if ( *(v8 + 148) & 0xF00 )
  {
    *(v8 + 4) = 1;
  }
  else
  {
    *(v8 + 4) = 0;
  }
  switch ( *(v8 + 4) )
  {
    case 0:
      *v1 = BYTE1(v9);
      *(v1 + 1) = 0;
      *(v1 + 2) = v9;
      *(v1 + 3) = 68;
      *(v1 + 4) = BYTE1(v9);
      *(v1 + 5) = 0;
      *(v1 + 6) = v9;
      *(v1 + 7) = 12;
      *(v1 + 8) = BYTE3(v9);
      *(v1 + 9) = 0;
      *(v1 + 10) = BYTE2(v9);
      *(v1 + 11) = 21;
      *(v1 + 12) = BYTE3(v9);
      *(v1 + 13) = 0;
      *(v1 + 14) = BYTE2(v9);
      *(v1 + 15) = 88;
      break;
    case 1:
      *v1 = v9;
      *(v1 + 1) = 0;
      *(v1 + 2) = BYTE1(v9);
      *(v1 + 3) = 21;
      *(v1 + 4) = BYTE2(v9);
      *(v1 + 5) = 0;
      *(v1 + 6) = BYTE3(v9);
      *(v1 + 7) = 12;
      *(v1 + 8) = BYTE2(v9);
      *(v1 + 9) = 0;
      *(v1 + 10) = BYTE1(v9);
      *(v1 + 11) = 68;
      *(v1 + 12) = v9;
      *(v1 + 13) = 0;
      *(v1 + 14) = BYTE1(v9);
      *(v1 + 15) = 88;
      break;
    case 3:
      *v1 = BYTE1(v9);
      *(v1 + 1) = v9;
      *(v1 + 2) = BYTE1(v9);
      *(v1 + 3) = v9;
      *(v1 + 4) = BYTE2(v9);
      *(v1 + 5) = BYTE3(v9);
      *(v1 + 6) = BYTE2(v9);
      *(v1 + 7) = BYTE3(v9);
      *(v1 + 8) = BYTE3(v9);
      *(v1 + 9) = BYTE2(v9);
      *(v1 + 10) = BYTE3(v9);
      *(v1 + 11) = BYTE2(v9);
      *(v1 + 12) = v9;
      *(v1 + 13) = BYTE1(v9);
      *(v1 + 14) = v9;
      *(v1 + 15) = BYTE1(v9);
      break;
    case 2:
      *v1 = v9;
      *(v1 + 1) = BYTE1(v9);
      *(v1 + 2) = BYTE1(v9);
      *(v1 + 3) = BYTE2(v9);
      *(v1 + 4) = BYTE2(v9);
      *(v1 + 5) = BYTE2(v9);
      *(v1 + 6) = BYTE1(v9);
      *(v1 + 7) = BYTE3(v9);
      *(v1 + 8) = v9;
      *(v1 + 9) = BYTE3(v9);
      *(v1 + 10) = BYTE1(v9);
      *(v1 + 11) = BYTE1(v9);
      *(v1 + 12) = BYTE3(v9);
      *(v1 + 13) = BYTE3(v9);
      *(v1 + 14) = BYTE1(v9);
      *(v1 + 15) = v9;
      break;
    default:
      break;
  }
  if ( v15 >= 0x10 )
  {
    operator delete(v13);
  }
  if ( v12 >= 8 )
  {
    operator delete(v10);
  }
  return 1;
}
warrenarea commented 7 years ago

it appears MiniFire's key he found, was Case 1

just not sure if its putting these keys all together during run-time. but, remember, MiniFire first found something that looked like the right key, then he found another one that actually worked.

yeah if memory serves me... it was Case 2, because it had all SN digits.

so i think its safe to say, its doing it like the Epoc model, and putting each of the keys together at run-time. From the code alone, you would make the conclusion that it would only go to one Switch Case, but it doesn't do that that. (which is kind of odd)

warrenarea commented 7 years ago

but now we know.... that there is more than 2 keys for Epoc+ but actually 4. and we might take it a step further and suggest, that maybe each key is for a different Epoc+ mode setting, and not just a research version, like the Epoc.

warrenarea commented 7 years ago

There seems to be a bit more. After looking around the Epoc+ neighborhood, I found another crypt function. Some of the values kind of look like the values that was used for the Epoc research mode.

char __thiscall sub_1290D10(int this)
{
  int v1; // edi@1
  char *v2; // ecx@1
  char *v3; // eax@3
  _BYTE *v4; // ecx@3
  _BYTE *v5; // ecx@5
  char v6; // ST20_1@7
  int v7; // eax@7
  bool v8; // zf@11
  char v9; // al@11
  char v10; // cl@11
  int v12; // [sp+Ch] [bp-4Ch]@1
  int v13; // [sp+10h] [bp-48h]@7
  void *v14; // [sp+18h] [bp-40h]@1
  int v15; // [sp+28h] [bp-30h]@3
  unsigned int v16; // [sp+2Ch] [bp-2Ch]@1
  void *v17; // [sp+30h] [bp-28h]@3
  int v18; // [sp+40h] [bp-18h]@3
  unsigned int v19; // [sp+44h] [bp-14h]@3
  int v20; // [sp+54h] [bp-4h]@3

  v12 = this;
  v1 = this + 158;
  _mm_storeu_si128((this + 158), 0i64);
  (*(*this + 48))(&v14);
  v2 = &v14;
  if ( v16 >= 8 )
  {
    v2 = v14;
  }
  v20 = 0;
  v19 = 15;
  v3 = &v2[2 * v15];
  v18 = 0;
  v4 = &v14;
  LOBYTE(v17) = 0;
  if ( v16 >= 8 )
  {
    v4 = v14;
  }
  sub_11910C0(&v17, v4, v3, v12);
  v5 = &v17;
  if ( v19 >= 0x10 )
  {
    v5 = v17;
  }
  LOBYTE(v20) = 1;
  v13 = *v5;
  v6 = v5[4];
  v7 = (*(*v12 + 76))(v12);
  if ( *(v12 + 148) & 0xF00 )
  {
    *(v12 + 4) = 1;
  }
  else
  {
    *(v12 + 4) = 0;
  }
  if ( *(v12 + 4) == 1 )
  {
    v8 = v7 == 2;
    v9 = BYTE3(v13);
    v10 = BYTE2(v13);
    *v1 = v13;
    if ( v8 )
    {
      *(v1 + 1) = v13;
      *(v1 + 2) = BYTE1(v13);
      *(v1 + 3) = BYTE1(v13);
      *(v1 + 4) = BYTE2(v13);
      *(v1 + 5) = BYTE2(v13);
      *(v1 + 6) = BYTE3(v13);
      *(v1 + 7) = BYTE3(v13);
      *(v1 + 8) = v13;
      *(v1 + 9) = v13;
      *(v1 + 10) = BYTE1(v13);
      *(v1 + 11) = BYTE1(v13);
      *(v1 + 12) = BYTE2(v13);
      *(v1 + 13) = BYTE2(v13);
      *(v1 + 14) = BYTE3(v13);
      *(v1 + 15) = BYTE3(v13);
      goto LABEL_16;
    }
    *(v1 + 1) = 0;
    *(v1 + 2) = BYTE1(v13);
    *(v1 + 3) = 84;
    *(v1 + 4) = BYTE2(v13);
    *(v1 + 5) = 16;
    *(v1 + 6) = BYTE3(v13);
    *(v1 + 7) = 66;
    *(v1 + 8) = v13;
    *(v1 + 9) = 0;
    *(v1 + 10) = BYTE1(v13);
    *(v1 + 11) = 72;
  }
  else
  {
    *v1 = v13;
    *(v1 + 1) = 0;
    *(v1 + 2) = BYTE1(v13);
    *(v1 + 3) = 72;
    *(v1 + 4) = v13;
    v10 = BYTE2(v13);
    *(v1 + 5) = 0;
    *(v1 + 6) = BYTE1(v13);
    v9 = BYTE3(v13);
    *(v1 + 7) = 84;
    *(v1 + 8) = BYTE2(v13);
    *(v1 + 9) = 16;
    *(v1 + 10) = BYTE3(v13);
    *(v1 + 11) = 66;
  }
  *(v1 + 12) = v10;
  *(v1 + 13) = 0;
  *(v1 + 14) = v9;
  *(v1 + 15) = 80;
LABEL_16:
  if ( v19 >= 0x10 )
  {
    operator delete(v17);
  }
  if ( v16 >= 8 )
  {
    operator delete(v14);
  }
  return 1;
}
warrenarea commented 7 years ago

Nested in Epoc+ functions, I suspect this might be important... it does kind of remind me though, of the Epoc get_level, but was kind of simplified.

the (this + #) is addressing specific variables, from its prior function.


int __thiscall sub_1292740(int this, int a2)
{
  int result; // eax@2

  if ( a2 )
  {
    *(this + 144) = (*a2 != 0) + 1;
    *(this + 150) = *(a2 + 1) | (*(a2 + 2) << 8);
    *(this + 152) = *(a2 + 3);
    *(this + 154) = *(a2 + 4);
    result = *(a2 + 5);
    *(this + 156) = result;
  }
  return result;
}
warrenarea commented 7 years ago

i best let everyone catch up. much to digest here.

ron-weiner commented 7 years ago

hey @warrenarea , i've just joined this discussion and i'm not sure if you are reversing the newest Epoc+(2016+) or the Epoc+(Pre-2016).

i want to know if it's relevant for the one that i got.

tnx

ghost commented 7 years ago

https://github.com/openyou/emokit/issues/256#issuecomment-304988499

Signal quality level matches up pretty nicely, but battery could be too.

On the indicator in their program is it 4-5 bars for battery level?

ghost commented 7 years ago

https://github.com/openyou/emokit/issues/256#issuecomment-304743385

  1. v6[1] = floor(8192.0 - (v6[1] - 8192.0));
  2. v6[10] = floor(8192.0 - (v6[10] - 8192.0));
  3. v6[15] = floor(8192.0 - (v6[15] - 8192.0));

This is very interesting. To me this indicates 3 values are combined to create the whole float/double. Well kind of anyhow, it changes the calculation significantly from what we were doing.

ghost commented 7 years ago

A semi-pythonized version:

second_bit should be byte.

import math

def level_calc(a1, second_bit, a3, sensor_count, a5, current_sensor):
    result = 0
    v6 = 0
    v7 = 0
    v8 = a3
    v35 = 0
    v36 = 0
    v37 = 0
    v40 = 0

#
# int __stdcall sub_1252AB0(int a1, int a2, int a3, signed int a4, int a5, int a6)
#{
#  int *v6; // edx@1
#  int *v7; // esi@1
#  int v8; // ecx@1
#  int result; // eax@2
#  int v10; // ebx@3
#  signed int v11; // edi@4 byte_position?
#  unsigned int v12; // esi@5 total_bytes?
#  int v13; // eax@6
#  int v14; // eax@9
#  int v15; // ecx@21
#  int v16; // ecx@21
#  int v17; // ecx@21
#  int v18; // ecx@21
#  int v19; // ecx@21
#  int v20; // ecx@21
#  signed int v21; // ebx@22 bit?
#  signed int v22; // eax@26
#  int v23; // edi@27 sensor_value?
#  int v24; // ecx@27
#  signed int v25; // esi@28
#  int v26; // edi@29
#  int v27; // edx@29
#  int v28; // eax@29
#  unsigned int v29; // edx@31
#  _DWORD *v30; // edx@31
#  int v31; // eax@36
#  bool v32; // zf@42
#30.   int v33; // ecx@46
#31.   void *v34; // [sp+10h] [bp-24h]@1
#32.   int *v35; // [sp+14h] [bp-20h]@1
#33.   int *v36; // [sp+18h] [bp-1Ch]@1
#34.   int v37; // [sp+1Ch] [bp-18h]@1
#35.   int v38; // [sp+20h] [bp-14h]@31
#36.   int v39; // [sp+24h] [bp-10h]@10
#37.   int v40; // [sp+30h] [bp-4h]@1
#38.
    if not a3:
        # a3 must be positive.
        result = a1
        # not sure why all this is happening though.
        #*a1 = a3
        #*(a1 + 4) = v8
        #*(a1 + 8) = v8
        # since we exit here.
        return result
    v10 = 0
    if second_bit > 0:
        byte_position = 2 # <--- start at position 2 in data frame 0 - counter 1 - packet type 2 - sensor data
        # A4 must be 0 sometimes, the differentiators between epoc+ and epoc it seems... sensor count?
        if (sensor_count + 2) > 2:
            total_bytes = sensor_count + 2
            # Process Epoc+ data.
            while True:
                v13 = second_bit
                if not (byte_position % 2):
                    v10 = byte_position + v8
                    #goto LABEL_15; which is:
                    if byte_position == 17 and v13 == 16:
                        current_sensor = 0
                        # (sub_12C52D0)(&current_sensor) <--- interesting function. what is it?
                    v8 = a3
                    if ++byte_position >= total_bytes:
                        v7 = v35
                        v6 = v34
                        break
                if second_bit == 32:
                    # Extra packet stuff.
                    v14 = (v10 | (*(byte_position + v8) << 8))
                    if byte_position == 5:
                        v39 = (0x8000 - v14) >> 2
                    else:
                        v39 = (v14 + 0x8000) >> 2
                else:
                    if second_bit != 16:
                        # GOTO LABEL_15; which is:
                        # If second bit is not Epoc+, setup values and break.
                        if byte_position == 17 and v13 == 16:
                            current_sensor = 0
                            # (sub_12C52D0)(&current_sensor) <--- interesting function. what is it?
                        v8 = a3
                        if ++byte_position >= total_bytes:
                            v7 = v35
                            v6 = v34
                            break
                    v39 = (*(byte_position + v8) << 8) | v10
                # (sub_12C52D0)(&v39); <--- interesting function. what is it?
                v10 = v39
                v13 = second_bit
            # LABEL_15:
                if byte_position == 17 and v13 == 16:
                    current_sensor = 0
                    # (sub_12C52D0)(&a6)
                v8 = a3
                if ++byte_position >= total_bytes:
                     v7 = v35
                     v6 = v34
                     break
        if second_bit == 32:
            second_bit = 0
            # Do stuff for odd packet setup. 16 vs 32
            # (sub_12C52D0)(&a2);
            v6 = v34 # No pointer
            v7 = v35 # No pointer
            v15 = *v34 # Pointer
            *v34 = *(v34 + 2) # Reference address of v34 + 2 assign to pointer value
            v6[2] = v15
            v16 = *v6
            *v6 = v6[1]
            v6[1] = v16
            v17 = v6[3]
            v6[3] = v6[5]
            v6[5] = v17
            v18 = v6[3]
            v6[3] = v6[4]
            v6[4] = v18
            v19 = v6[6]
            v6[6] = v6[8]
            v6[8] = v19
            v20 = v6[6]
            v6[6] = v6[7]
            v6[7] = v20
      # goto LABEL_46; which is:

        result = a1
        v33 = v36
        #*a1 = v6
        #*(a1 + 4) = v7
        #*(a1 + 8) = v33
        return result
    bit = a5

    if 8 * sensor_count >= (current_sensor * a5):
        second_bit = 0
        v22 = 1
        sensor_count = 1
        if not current_sensor:
        # LABEL_44:
            if (v7 - v6) >= 0x10:
                v6[1] = math.floor(8192.0 - (v6[1] - 8192.0))
                v6[10] = math.floor(8192.0 - (v6[10] - 8192.0))
                v6[15] = math.floor(8192.0 - (v6[15] - 8192.0))
            # LABEL_46:
            result = a1
            v33 = v36
            #*a1 = v6
            #*(a1 + 4) = v7
            #*(a1 + 8) = v33
            return result
        while True:
            sensor_value = 0
            v24 = 8 - second_bit
            if a5 > 8 - second_bit:
                v25 = sensor_count
                second_bit = 0
                while bit > 8:
                    bit -= v24
                    v26 = sensor_value << v24
                    v27 = *(v25++ + a3)
                    v28 = (1 << v24) - 1
                    v24 = 8
                    sensor_value = v28 & v27 | v26
                sensor_count = v25
                v7 = v35
                v22 = sensor_count
            second_bit += bit
            v29 = (sensor_value << bit) | ((1 << bit) - 1) & (*(v22 + a3) >> (v24 - bit))
            v38 = v29
            v39 = v29
            v30 = v34
            if &v39 >= v7 or v34 > &v39:
                if v7 == v36:
                    (vector_list)(1)
                    v7 = v35
                if v7:
                    v31 = v38
            else:
                 if v7 == v36:
                   (vector_list)(1)
                   v7 = v35
                   v30 = v34
                 if v7:
                    v31 = v30[(&v39 - v34) >> 2]
            if v7:
                *v7 = v31
            v22 = sensor_count
            v7 += 1
            v32 = current_sensor - - == 1
            bit = a5
            v35 = v7
            if v32:
                v6 = v34
                # goto LABEL_44; which is:
                if (v7 - v6) >= 0x10:
                    v6[1] = math.floor(8192.0 - (v6[1] - 8192.0))
                    v6[10] = math.floor(8192.0 - (v6[10] - 8192.0))
                    v6[15] = math.floor(8192.0 - (v6[15] - 8192.0))
                # LABEL_46:
                result = a1
                v33 = v36
                # *a1 = v6
                # *(a1 + 4) = v7
                # *(a1 + 8) = v33
                return result
    # (sub_112D5B0)(&v34)
    if v34:
        # operator delete(v34);
        pass
    return a1
warrenarea commented 7 years ago

rsubrosa, its relevant, because we're looking at a bit of both.

warrenarea commented 7 years ago

bill, line #38 you said you weren't sure about some data being set at the function exit.

     #*a1 = a3
     #*(a1 + 4) = v8
     #*(a1 + 8) = v8

The * indicates that its pointing to an address in memory. the +4 and +8 are just telling it to move a couple byte segments down in the stack. basically its just setting the values of a few variables.

i think they're being used like "global" variables. which are then likely utilized in the functions that called this function.

when i viewed the data from one of them, one was a raw data value from a sensor. (4 bytes) and then another was an 8 byte hex value, not sure what it was, but i could check.

ghost commented 7 years ago

Can you post the values?

ghost commented 7 years ago

All of the a variables would be nice to see.

warrenarea commented 7 years ago

From time to time, i find some references to sprintf that seems like there is some debug information being output to a file. It makes sense they might incorporate some sort of command line into the program... and I did find a string that said something like

C:\edk_internal_log.txt

not sure if its just something completely different.

so then i figured, that this product probably wouldn't use something like a command line argument. Because all of the licensing and session data is all handled via registry data.

When you go to enter an offline license key, it looks for a file in the local folder.

so i started poking around for the registry entries, and i found this...

rdata:014BFE10 aEsvn db 'Esvn',0                       ; DATA XREF: sub_1161C30+2o
.rdata:014BFE15 align 4
.rdata:014BFE18 aEdk db '/EDK',0                        ; DATA XREF: sub_1161CB0+2o
.rdata:014BFE1D align 10h
.rdata:014BFE20 aEsvn_bin db '/Esvn.bin',0              ; DATA XREF: sub_1161C90+2o
.rdata:014BFE2A align 4
.rdata:014BFE2C aEkvn_bin db '/Ekvn.bin',0              ; DATA XREF: sub_1161C70+2o
.rdata:014BFE36 align 4
.rdata:014BFE38 aEcvn_bin db '/Ecvn.bin',0              ; DATA XREF: sub_1161C50+2o
.rdata:014BFE42 align 4
.rdata:014BFE44 aEo db '\EO',0                          ; DATA XREF: sub_1161D10+3Co
.rdata:014BFE48 aSoftwareMicros db 'Software\Microsoft\',0 ; DATA XREF: sub_1161D10+31o
.rdata:014BFE5C aCanYouHackMe_P db 'Can you hack me. ph',0 ; DATA XREF: sub_1161CD0+2o
.rdata:014BFE70 aMayIHackYou_Ph db 'May I hack you. ph',0 ; DATA XREF: sub_1161CF0+2o
.rdata:014BFE83 align 4
.rdata:014BFE84 aEmotiv db '/Emotiv',0                  ; DATA XREF: sub_1228640+94o
.rdata:014BFE8C aLcc db 'LCC',0                         ; DATA XREF: sub_12276E0+1D0o
.rdata:014BFE8C                                         ; sub_1228170+B3o
.rdata:014BFE90 aLhc db 'LHC',0                         ; DATA XREF: sub_1225F90:loc_1226201o
.rdata:014BFE90                                         ; sub_1226FA0+35Fo ...
.rdata:014BFE94 aB835800 db 'b835800',0                 ; DATA XREF: sub_1228A00o
.rdata:014BFE9C a3_4_0 db '3.4.0',0                     ; DATA XREF: sub_12289F0o
.rdata:014BFEA2 align 4
.rdata:014BFEA4 a3_4_3 db '3.4.3',0                     ; DATA XREF: sub_1228A10o
.rdata:014BFEAA align 4
.rdata:014BFEAC aEmotivV1_0_7 db 'Emotiv v1.0',0
.rdata:014BFEB8 aEmotivV2_0_7 db 'Emotiv v2.0',0

the interesting part being the strings...

 'Can you hack me. ph',
 'May I hack you. ph'

funny stuff. I think some of the registry or subkeys, have something to do with LCC or LHC and b835800

obviously someone who actually purchased it, would be able to tell us right off.

warrenarea commented 7 years ago

b835800 is just the build number.

warrenarea commented 7 years ago

i managed to patch it so that it thinks i'm signed in off-line mode, at least partially. it says i'm signed in but doesn't record.

warrenarea commented 7 years ago

to answer your previous question about the battery level.... it shows a green bar in those 4-5 chunks. i changed the result status in real-time, and it instantly changed.

ghost commented 7 years ago

Very nice

warrenarea commented 7 years ago

(sub_12C52D0)(&current_sensor) <--- interesting function. what is it?

my ida project file got corrupted, think it analyzed it slightly different than what i posted earlier. sub_13C52D0(&v35, &a6); I didn't include much information on this one, because it didn't look very interesting. think its possibly a concat method, and makes reference to a vector. The function itself is called hundreds of times in the code, so I suspect its just a simple C command dealing with an array.

(sub_112D5B0)(&v34)

This one is more interesting than the previous one, but not by much. lol just sets a bunch of global variables to 0.

I was going to post every value for every single variable, but it would take ages, because a good portion of the variables are stack references. However, I think I was making some headway focusing on just a few specific ones. I'm pretty sure I was seeing the bits[i] values in action.

ghost commented 7 years ago

The application gets loaded into different locations in memory so the memory address of the functions changed is all.

That makes sense, cleaning up memory probably.

I would like to see what it's doing with the array, is it storing the sensor value or getting a value?

Also, what function calls sub_1252AB0, the level math function? What does it do with the value returned?

ron-weiner commented 7 years ago

hey guys. i'm sorry for being a nood and maybe bugging you a bit. it there i way to catch up with the basic initialization for the tests you do? I'd like to join u and try to help where i can..

ghost commented 7 years ago

@rsubrosa You're going to need IDA, there are some links here that should help you out:

https://www.hex-rays.com/products/ida/support/links.shtml

ron-weiner commented 7 years ago

@bschumacher tnx i'll join u guys soon...

warrenarea commented 7 years ago

sub_1252ab0 is called by 1252f80()

int __stdcall sub_1252F80(int a1, int a2, int a3, int a4)
{
  sub_1252AB0(a1, a2, a3, a4, 14, 16);
  return a1;
}

which is a function called from...

int __thiscall sub_12503A0(void *this, int a2, int a3)
{
  void *v3; // ebx@1
  int v4; // edi@1
  int i; // esi@1
  unsigned int v6; // ecx@3
  int v7; // eax@3
  unsigned int v8; // eax@6
  unsigned int v9; // edx@6
  signed int v10; // edi@6
  unsigned int v11; // ecx@7
  int v12; // ecx@11
  unsigned __int8 v13; // al@19
  bool v14; // sf@19
  int v15; // eax@20
  void *v16; // eax@22
  unsigned int v17; // edx@22
  int v18; // edi@22
  __m128i v19; // xmm1@22
  int v20; // ecx@22
  __m128i v21; // xmm0@22
  void *v22; // eax@22
  void *v24; // [sp+14h] [bp-90h]@22
  int v25; // [sp+20h] [bp-84h]@1
  void *v26; // [sp+24h] [bp-80h]@6
  int v27; // [sp+28h] [bp-7Ch]@6
  int v28; // [sp+30h] [bp-74h]@1
  char Dst; // [sp+34h] [bp-70h]@1
  int v30; // [sp+38h] [bp-6Ch]@3
  int v31; // [sp+3Ch] [bp-68h]@3
  int v32; // [sp+40h] [bp-64h]@14
  __m128i v33; // [sp+44h] [bp-60h]@6
  int v34; // [sp+54h] [bp-50h]@22
  int v35; // [sp+60h] [bp-44h]@13
  __int128 v36; // [sp+64h] [bp-40h]@22
  __int128 v37; // [sp+74h] [bp-30h]@22
  unsigned int v38; // [sp+84h] [bp-20h]@17
  unsigned int v39; // [sp+88h] [bp-1Ch]@17
  unsigned int v40; // [sp+8Ch] [bp-18h]@17
  unsigned int v41; // [sp+90h] [bp-14h]@4
  int v42; // [sp+A0h] [bp-4h]@1

  v3 = this;
  v4 = a2;
  v25 = a2;
  *a2 = 0;
  *(a2 + 4) = 0;
  *(a2 + 8) = 0;
  v42 = 0;
  v28 = 1;
  memset(&Dst, 0, 0x60u);
  for ( i = *a3; i != *(a3 + 4); *(v3 + 55) += (*(v4 + 4) - *v4) / 96 )
  {
    if ( (*(*v3 + 76))(v3) == 2 )
    {
      v6 = *(i + 1);
      v30 = *i;
      v7 = v6 & 0x7F;
      v31 = v7;
      if ( v7 == 16 )
        v41 = v6 >> 7;
      else
        v41 = 0;
      sub_1252F80(&v26, v7, i, 30);
      v8 = 0;
      v9 = (v27 - v26) >> 2;
      v10 = v26 - &v33;
      while ( 1 )
      {
        v11 = 16;
        if ( v9 < 0x10 )
          v11 = v9;
        if ( v8 >= v11 )
          break;
        v33.m128i_i32[v8] = *(&v33.m128i_i32[v8] + v10);
        ++v8;
      }
      v12 = v31;
      if ( v30 != *(v3 + 75) - 1 || v31 != 16 )
      {
        v32 = *(v3 + 49);
        if ( v31 == 32 )
          *(v3 + 23) = v33.m128i_i64[0];
      }
      else if ( v35 )
      {
        v32 = v35 & 0x7F;
        *(v3 + 49) = v32;
      }
      v38 = *(v3 + 46);
      v39 = *(v3 + 47);
      v40 = v12;
      if ( v26 )
      {
        operator delete(v26);
        v26 = 0;
        v27 = 0;
      }
    }
    else
    {
      v13 = *i;
      v14 = *i < 0;
      v31 = 0;
      if ( v14 )
      {
        v15 = v13 & 0x7F;
        v30 = 128;
        *(v3 + 49) = v15;
      }
      else
      {
        v30 = v13;
        v15 = *(v3 + 49);
      }
      v32 = v15;
      sub_1252F80(&v24, 0, i, 32);
      v16 = v24;
      v17 = *(i + 31);
      v18 = 16 * *(i + 29);
      v19 = _mm_loadu_si128(v24 + 2);
      v20 = 16 * *(i + 30);
      _mm_storeu_si128(&v33, _mm_loadu_si128(v24));
      v40 = v17;
      v21 = _mm_loadu_si128(v16 + 1);
      _mm_storeu_si128(&v36, v19);
      _mm_storeu_si128(&v34, v21);
      _mm_storeu_si128(&v37, _mm_loadu_si128(v16 + 3));
      v41 = (_mm_cvtsi128_si32(v19) >> 13) & 1;
      v38 = (v17 >> 4) | v18;
      *(v3 + 46) = v38;
      v22 = v24;
      v39 = v17 & 0xF | v20;
      *(v3 + 47) = v39;
      if ( v22 )
      {
        operator delete(v22);
        v24 = 0;
      }
    }
    v4 = v25;
    sub_1251AE0(v25, &Dst);
    i += 32;
  }
  return v4;
}
sub_1252F80(&v26, v7, i, 30);
sub_1252F80(&v24, 0, i, 32);

i think v26 and v24 get filled with the result of the function. or the & probably mean its returning a memory reference.

every now and then i'll notice while stepping through the code, that the instructions sometimes jumps back a few lines and executes some code twice.... Doesn't happen too often, but should be a reminder that hex-rays isn't 100% precise, or maybe the code is still accurate, but certain assembly instructions might make the line marker jump backwards. as certain assembly instructions can be kind of complicated that way.

warrenarea commented 7 years ago

i think you'll find there are some useful math functions after the get_level handling function.

shifting by 4 and 13 and some AND, OR

the bottom sub 1251ae0

int __thiscall sub_1251AE0(int this, unsigned int a2)
{
  int v2; // esi@1
  unsigned int v3; // ecx@1
  unsigned int v4; // edx@3
  int v5; // edi@3
  int v6; // ecx@5
  int result; // eax@5

  v2 = this;
  v3 = *(this + 4);
  if ( a2 >= v3 || *v2 > a2 )
  {
    if ( v3 == *(v2 + 8) )
      sub_50FAD0(1);
    result = *(v2 + 4);
    if ( result )
    {
      _mm_storeu_si128(result, _mm_loadu_si128(a2));
      _mm_storeu_si128((result + 16), _mm_loadu_si128((a2 + 16)));
      _mm_storeu_si128((result + 32), _mm_loadu_si128((a2 + 32)));
      _mm_storeu_si128((result + 48), _mm_loadu_si128((a2 + 48)));
      _mm_storeu_si128((result + 64), _mm_loadu_si128((a2 + 64)));
      _mm_storeu_si128((result + 80), _mm_loadu_si128((a2 + 80)));
    }
  }
  else
  {
    v4 = ((715827883i64 * (a2 - *v2)) >> 32) >> 4;
    v5 = v4 + (v4 >> 31);
    if ( v3 == *(v2 + 8) )
      sub_50FAD0(1);
    v6 = *(v2 + 4);
    result = *v2 + 96 * v5;
    if ( v6 )
    {
      _mm_storeu_si128(v6, _mm_loadu_si128(result));
      _mm_storeu_si128((v6 + 16), _mm_loadu_si128((result + 16)));
      _mm_storeu_si128((v6 + 32), _mm_loadu_si128((result + 32)));
      _mm_storeu_si128((v6 + 48), _mm_loadu_si128((result + 48)));
      _mm_storeu_si128((v6 + 64), _mm_loadu_si128((result + 64)));
      _mm_storeu_si128((v6 + 80), _mm_loadu_si128((result + 80)));
      *(v2 + 4) += 96;
      return result;
    }
  }
  *(v2 + 4) += 96;
  return result;
}
warrenarea commented 7 years ago

Not sure how helpful this is, but here is the function for switching to different modes.

int __thiscall sub_421D80(void *this)
{
  void *v1; // edi@1
  int v2; // ecx@1
  int v3; // eax@1
  int v4; // eax@5
  int v5; // eax@11
  int v6; // eax@17
  int v7; // eax@25
  const struct QString *v8; // eax@33
  QLabel *v9; // ecx@33
  const struct QString *v10; // eax@33
  QLabel *v11; // ecx@33
  const struct QString *v12; // eax@33
  QLabel *v13; // ecx@33
  const struct QString *v14; // eax@33
  QLabel *v15; // ecx@33
  const struct QString *v16; // eax@33
  QLabel *v17; // ecx@33
  char v19; // [sp+Ch] [bp-3Ch]@33
  int v20; // [sp+10h] [bp-38h]@1
  int v21; // [sp+14h] [bp-34h]@1
  int v22; // [sp+18h] [bp-30h]@1
  int v23; // [sp+1Ch] [bp-2Ch]@1
  int v24; // [sp+20h] [bp-28h]@1
  int v25; // [sp+24h] [bp-24h]@1
  int v26; // [sp+28h] [bp-20h]@5
  int v27; // [sp+2Ch] [bp-1Ch]@11
  struct QString::Data *v28; // [sp+30h] [bp-18h]@1
  int v29; // [sp+34h] [bp-14h]@17
  int v30; // [sp+38h] [bp-10h]@25
  int v31; // [sp+44h] [bp-4h]@1

  v1 = this;
  v28 = QString::fromAscii_helper("   ", -1);
  v2 = *(v1 + 151);
  v31 = 0;
  sub_40E880(&v20, &v22, &v21, &v25, &v24);
  v23 = QString::shared_null;
  _InterlockedExchangeAdd(QString::shared_null, 1u);
  v3 = v20;
  LOBYTE(v31) = 1;
  if ( !v20 )
  {
    QString::operator=(&v23, "EPOC");
    v3 = v20;
  }
  if ( v3 == 1 )
    QString::operator=(&v23, "EPOC+");
  v26 = QString::shared_null;
  _InterlockedExchangeAdd(QString::shared_null, 1u);
  v4 = v22;
  LOBYTE(v31) = 2;
  if ( !v22 )
  {
    QString::operator=(&v26, "128 Hz");
    v4 = v22;
  }
  if ( v4 == 1 )
  {
    QString::operator=(&v26, "256 Hz");
    v4 = v22;
  }
  if ( v4 == 2 )
    QString::operator=(&v26, "0");
  v27 = QString::shared_null;
  _InterlockedExchangeAdd(QString::shared_null, 1u);
  v5 = v21;
  LOBYTE(v31) = 3;
  if ( !v21 )
  {
    QString::operator=(&v27, "14 bit");
    v5 = v21;
  }
  if ( v5 == 1 )
  {
    QString::operator=(&v27, "16 bit");
    v5 = v21;
  }
  if ( v5 == 2 )
    QString::operator=(&v27, "0");
  v29 = QString::shared_null;
  _InterlockedExchangeAdd(QString::shared_null, 1u);
  v6 = v25;
  LOBYTE(v31) = 4;
  if ( !v25 )
  {
    QString::operator=(&v29, "0");
    v6 = v25;
  }
  if ( v6 == 1 )
  {
    QString::operator=(&v29, "32Hz");
    v6 = v25;
  }
  if ( v6 == 2 )
  {
    QString::operator=(&v29, "64Hz");
    v6 = v25;
  }
  if ( v6 == 3 )
    QString::operator=(&v29, "128Hz");
  v30 = QString::shared_null;
  _InterlockedIncrement(QString::shared_null);
  v7 = v24;
  LOBYTE(v31) = 5;
  if ( !v24 )
  {
    QString::operator=(&v30, "12 bit");
    v7 = v24;
  }
  if ( v7 == 1 )
  {
    QString::operator=(&v30, "14 bit");
    v7 = v24;
  }
  if ( v7 == 2 )
  {
    QString::operator=(&v30, "16 bit");
    v7 = v24;
  }
  if ( v7 == 3 )
    QString::operator=(&v30, "0");
  v8 = sub_4061E0(&v19, &v28, &v23);
  v9 = *(v1 + 187);
  LOBYTE(v31) = 6;
  QLabel::setText(v9, v8);
  LOBYTE(v31) = 5;
  QString::~QString(&v19);
  v10 = sub_4061E0(&v19, &v28, &v26);
  v11 = *(v1 + 188);
  LOBYTE(v31) = 7;
  QLabel::setText(v11, v10);
  LOBYTE(v31) = 5;
  QString::~QString(&v19);
  v12 = sub_4061E0(&v19, &v28, &v27);
  v13 = *(v1 + 189);
  LOBYTE(v31) = 8;
  QLabel::setText(v13, v12);
  LOBYTE(v31) = 5;
  QString::~QString(&v19);
  v14 = sub_4061E0(&v19, &v28, &v29);
  v15 = *(v1 + 190);
  LOBYTE(v31) = 9;
  QLabel::setText(v15, v14);
  LOBYTE(v31) = 5;
  QString::~QString(&v19);
  v16 = sub_4061E0(&v19, &v28, &v30);
  v17 = *(v1 + 191);
  LOBYTE(v31) = 10;
  QLabel::setText(v17, v16);
  LOBYTE(v31) = 5;
  QString::~QString(&v19);
  LOBYTE(v31) = 4;
  QString::~QString(&v30);
  LOBYTE(v31) = 3;
  QString::~QString(&v29);
  LOBYTE(v31) = 2;
  QString::~QString(&v27);
  LOBYTE(v31) = 1;
  QString::~QString(&v26);
  LOBYTE(v31) = 0;
  QString::~QString(&v23);
  v31 = -1;
  return QString::~QString(&v28);
}

also something of brief interest.

    v3 = QString::fromAscii_helper(
           "Your EPOC+ firmware 0x610 does not permit changing to EPOC+ mode.Please contact hello@emotiv.com to arrange f"
           "or a firmware update.",
           -1);
ghost commented 7 years ago

What else is in the function that has that message?

warrenarea commented 7 years ago

Bill, i was thinking the other day. i think we should construct another test for minifiredragon like we did a month ago.

Because I think its clear that there is multiple key setups for the Epoc+

Was thinking, too bad we couldn't associate a key, to shift through the different key setups.... so we can say Epoc+ 128hz worked in Mode 1, but not in Mode 2.

Might make it easy for us to cycle through them.

Also.... I looked again at the data produced by the results that were producing a viable counter. Tried big endian conversions, and nothing seemed to look right. Obviously its probably being converted a little differently... but also knowing, the exact function where the keys are coming from, we should be able to verify with certainty which ones are being used.

remember in the case of my Epoc, it would combine even the research key, so what minifire saw in his IDA output, was just 2 possible outcomes, when there is a few more we need tried.

the fact that the counter was consistently being decrypted though, makes it likely that we were looking at the correct data though.

think i should probably just keep at sorting out the get_level

ghost commented 7 years ago

Agreed, wouldn't it be cool if we could change the mode without using their control panel?

Definitely worth investigating.

I think we got the whole get_level code here already, but I think I need to install Windows and look at it in real time with the values in the variables to completely understand what they're doing.

warrenarea commented 7 years ago

it was just some function to update the settings i think.

it was part of sub_427130()

v21 = sub_403B20(
                &v25,
                "Update failed. Please attach the cable to the headset in order to update the settings. Error ",
                v20);

"setting failed. Error"
"success"

and that function links back to a function sub_455ec0() which has a huge Switch() case that links back to 93 individual functions. i think its part of a "Main" loop, that delegates what each of the buttons do in the user interface. why it was referencing the UI for changing the epoc mode.

warrenarea commented 7 years ago

yes, its definitely helpful to look at them in real-time... but been so distracted by discovering other stuff, haven't tried to sort it out proper. I am pretty certain though it was producing very similar bit data as get_level.

at the same time.... i have been scouring, looking for sensor_bit and qualitybits values,

closest i seem to find, is there are a lot of divisions by 104, this seemed significant, but have seen so many numbers, they all start to seem significant. think that is part of the reason why I haven't given up finding more functions... because seems like there are still plenty of treasure troves of functions/information.

warrenarea commented 7 years ago

something to consider though, is that the Epoc+ firmware can probably be updated remotely now... which might potentially hinder us in the future. lol

warrenarea commented 7 years ago

i also uncovered a HTTP-like communication it makes with their server, that updates the licensing information... and updates registry information concerning date and usage... basically the limitations of how many recordings you can make.

warrenarea commented 7 years ago

actually, i was wrong... the "Update failed" had nothing to do with updating the Epoc firmware. it was just part of the changing modes function. So no, i doubt they could change the firmware remotely.

warrenarea commented 7 years ago

So at line 167 in the post above (with the reference to 8192 (posted on may 29) in function sub_1252AB0

        do
        {
          v21 -= v24;
          v26 = v23 << v24;
          v27 = *(v25++ + a3);
          v28 = (1 << v24) - 1;
          v24 = 8;
          v23 = v28 & v27 | v26;
        }
        while ( v21 > 8 );
        a4 = v25;
        v7 = v36;
        v22 = a4;
      }
      a2 += v21;
      v29 = (v23 << v21) | ((1 << v21) - 1) & (*(v22 + a3) >> (v24 - v21));

This is the critical code for Get_Level for the (Epoc Mode), not Epoc+ mind you.

Basically it is starting at 0, and building the data up bit by bit. Where the final result of the data is v29.

warrenarea commented 7 years ago

I am renaming all of the variables with some success, i will post it soon. Think the renaming in the python translation mixed up a few things.

CaptainSmileyXL commented 7 years ago

This may not be helpful at all since I am late to comment and have been working on the Mac side (which the symbols are intact BTW, so getting an idea of what the functions are doing is a bit easier)... But I have found the decompiler snowman (https://derevenets.com) to be quite good.

ghost commented 7 years ago

@drneuronerd Would you upload or send me the dmg you are working with?

CaptainSmileyXL commented 7 years ago

@bschumacher If you are talking about the dmg for snowman, it is actually a GitHub project and I used the latest one found here (https://github.com/yegord/snowman/tree/v0.1.0). I don't think I made any real changes, but if it doesn't compile for you I can send you my bzip'd file. It's 66MB and I get the "Yowza, that's a big file." error from GitHub. As for the library itself, I have been working from the latest community release of Emotiv's SDK - their Mac framework library that's included.

EDIT: Be forewarned that snowman can be a bit finicky. It has been extremely resource intensive on occasion and sometimes it doesn't look like it is done with its analysis when it is. Might be because they show Linux and Windows as the supported platforms. But once it looks like it is done, simply right-mouse clicking on the function name and telling it to decompile seems to snap the program into reality and it works quite well.

warrenarea commented 7 years ago

Pretty sure I've found the area exclusive to the Epoc+ that does the get_level

I will post my modified version of the decompilation of the regular Epoc mode first though. so we don't get them confused.

I am certain this one is for the Epoc+ though, because it has the floor(8192 etc. plus, it is handling the data with _mm_storeu_si128 and _mm_storel_epi64

which is consistent with the data formats that would be used for the Epoc+ Also, my Epoc doesn't step into it, which is another good indicator its the Epoc+ Another good indicator, is that similar to the Epoc mode, there are a grouping of 4 functions for the handling.

There are a total of 3 IF-condition groupings of 4 functions that reference code similar to our original get_level.... which I believe is consistent with the different mode-types.

Furthermore, its within a function block that houses the key decryption for the Epoc+ I didn't see it initially because it was nested inside a clock function.

The Epoc data handling was also nested in a clock function, but it seems it might do it slightly different. Actually I think it probably still does the same thing, but the coding style is more modernized. Possibly due to a different person coding it... or a coder who has become more refined in his abilities. as the coding style looks a little more refined from the previous version.

So, pretty certain this is our Epoc+ data handler. I am going to continue on the Epoc-mode get_level, but if anyone wants to skip ahead and work with the Epoc+ mode, here is how to get to it.

Method 1. Jump to Address (G) Select the word "clock" and ()press X) or Jump to Xref to Operand then select the 14th function down. That should be it.

Method 2. Jump to Address (or press G) Type: WaitForSingleObject Jump to Xref to Operand (or press X) Select 2nd Entry: sub_244C00+137

It will help a great deal if you have hex-rays, but look for the 2nd routine call sub_240300 under WaitForSingleObject Select sub_240300 and Jump to Xref to Operand (or press X)

You should have 3 entries... Click on one of the first two. sub_241DA0. This should take you to the function, you will see 3 IF condition groups, that contains the 4 subfunctions for the Epoc+ data handling.

warrenarea commented 7 years ago

Another thing to note... and i'll address it after the Epoc get_level, is that in the byte_names, which I think is used to describe what order the sensor data goes in... there is a secondary counter called COUNTER_MEMS and another byte named called MARKER.... which obviously handles the Emotiv marker device. I'll post that section a bit later.... I also found the order in which Insight byte_names are used. Which isn't too hard, just do a search for "AF3" and eventually you'll find the function that handles the byte names.

warrenarea commented 7 years ago

going to be honest with you, and this might seem a bit daft, but i didn't really know what the MEMS feature even was. But I see now, that its all about using the Gyro. (which i was never really interested in as much anyways) Apparently the Epoc+ can detect not just X,Y movements but Z as well.

And the ability to change the MEMS feature, changes the rate at which these samples are provided, and whether its on or off. Which they say, turning it off, will provide the device with longer battery life for EEG. Also... that reminds me, I did see some new byte names for gyroscope, acceleration, magnetometer so will have to factor those in as well.... plus a new one called RAW_CQ (raw contact quality)

warrenarea commented 7 years ago
void *__thiscall sub_18F780(void *this, int a2, int a3)
{
  void *v3; // edi@1
  int v4; // ebx@1
  int v5; // eax@1
  void *v7; // [sp+14h] [bp-44h]@3
  int v8; // [sp+18h] [bp-40h]@3
  int v9; // [sp+1Ch] [bp-3Ch]@3
  void *v10; // [sp+20h] [bp-38h]@3
  int v11; // [sp+24h] [bp-34h]@3
  int v12; // [sp+28h] [bp-30h]@3
  int v13; // [sp+2Ch] [bp-2Ch]@54
  void *Src; // [sp+30h] [bp-28h]@3
  int v15; // [sp+40h] [bp-18h]@3
  unsigned int v16; // [sp+44h] [bp-14h]@3
  int v17; // [sp+54h] [bp-4h]@1

  v3 = this;
  sub_1917E0(0);
  *v3 = &off_46D0A4;
  v17 = 0;
  *(v3 + 20) = -1;
  sub_1353D0(v3 + 88);
  sub_1353D0(v3 + 336);
  *(v3 + 148) = 0;
  *(v3 + 149) = a3;
  *(v3 + 632) = 0;
  *(v3 + 159) = 0;
  *(v3 + 160) = 0;
  *(v3 + 159) = sub_195F70(0, 0);
  *(v3 + 696) = 0;
  *(v3 + 175) = 0;
  *(v3 + 176) = 0;
  *(v3 + 175) = sub_17CCC0(v3 + 700);
  *(v3 + 177) = 0;
  *(v3 + 178) = 0;
  *(v3 + 177) = sub_17CCC0(v3 + 708);
  v4 = v3 + 716;
  *v4 = 0;
  *(v4 + 4) = 0;
  *(v4 + 8) = 0;
  *(v3 + 182) = 0;
  *(v3 + 183) = 0;
  *(v3 + 184) = 0;
  *(v3 + 185) = 0;
  *(v3 + 186) = 0;
  *(v3 + 185) = sub_195F30(0, 0);
  *(v3 + 187) = 0;
  *(v3 + 188) = 0;
  *(v3 + 187) = sub_195F30(0, 0);
  LOBYTE(v17) = 9;
  v5 = Mtx_init(v3 + 760, 2);
  if ( v5 )
    std::_Throw_C_error(v5);
  sub_19D670(v3);
  v10 = 0;
  v11 = 0;
  v12 = 0;
  v7 = 0;
  v8 = 0;
  v9 = 0;
  LOBYTE(v17) = 12;
  v16 = 15;
  v15 = 0;
  LOBYTE(Src) = 0;
  sub_11C1E0(&Src, "COUNTER", 7u);
  if ( a2 == 2 )
  {
    LOBYTE(v17) = 13;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "INTERPOLATED", 12u);
    LOBYTE(v17) = 14;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "AF3", 3u);
    LOBYTE(v17) = 15;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "AF4", 3u);
    LOBYTE(v17) = 16;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "T7", 2u);
    LOBYTE(v17) = 17;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "T8", 2u);
    LOBYTE(v17) = 18;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "Pz", 2u);
    LOBYTE(v17) = 19;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "RAW_CQ", 6u);
    LOBYTE(v17) = 20;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
  }
  else
  {
    LOBYTE(v17) = 21;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "INTERPOLATED", 0xCu);
    LOBYTE(v17) = 22;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "AF3", 3u);
    LOBYTE(v17) = 23;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "F7", 2u);
    LOBYTE(v17) = 24;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "F3", 2u);
    LOBYTE(v17) = 25;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "FC5", 3u);
    LOBYTE(v17) = 26;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "T7", 2u);
    LOBYTE(v17) = 27;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "P7", 2u);
    LOBYTE(v17) = 28;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "O1", 2u);
    LOBYTE(v17) = 29;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "O2", 2u);
    LOBYTE(v17) = 30;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v16 = 15;
    v15 = 0;
    LOBYTE(Src) = 0;
    sub_11C1E0(&Src, "P8", 2u);
    LOBYTE(v17) = 31;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    sub_11B460(&Src, "T8");
    LOBYTE(v17) = 32;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    sub_11B460(&Src, "FC6");
    LOBYTE(v17) = 33;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    sub_11B460(&Src, "F4");
    LOBYTE(v17) = 34;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    sub_11B460(&Src, "F8");
    LOBYTE(v17) = 35;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    sub_11B460(&Src, "AF4");
    LOBYTE(v17) = 36;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    sub_11B460(&Src, "RAW_CQ");
    LOBYTE(v17) = 37;
    sub_14E2F0(&Src);
    LOBYTE(v17) = 12;
    if ( v16 >= 0x10 )
      operator delete(Src);
    v13 = 17;
    sub_2B52D0(&v13);
    v13 = 16;
    sub_2B52D0(&v13);
    v13 = 1;
    sub_2B52D0(&v13);
    v13 = 2;
    sub_2B52D0(&v13);
    v13 = 3;
    sub_2B52D0(&v13);
    v13 = 4;
    sub_2B52D0(&v13);
    v13 = 5;
    sub_2B52D0(&v13);
    v13 = 6;
    sub_2B52D0(&v13);
    v13 = 50;
    sub_2B52D0(&v13);
    v13 = 51;
    sub_2B52D0(&v13);
    v13 = 9;
    sub_2B52D0(&v13);
    v13 = 10;
    sub_2B52D0(&v13);
    v13 = 11;
    sub_2B52D0(&v13);
    v13 = 12;
    sub_2B52D0(&v13);
    v13 = 13;
    sub_2B52D0(&v13);
    v13 = 14;
    sub_2B52D0(&v13);
    v13 = 34;
    sub_2B52D0(&v13);
  }
  sub_11B460(&Src, "COUNTER_MEMS");
  LOBYTE(v17) = 38;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "GYROSCOPEX");
  LOBYTE(v17) = 39;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "GYROSCOPEY");
  LOBYTE(v17) = 40;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "GYROSCOPEZ");
  LOBYTE(v17) = 41;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "ACCX");
  LOBYTE(v17) = 42;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "ACCY");
  LOBYTE(v17) = 43;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "ACCZ");
  LOBYTE(v17) = 44;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "MAGX");
  LOBYTE(v17) = 45;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "MAGY");
  LOBYTE(v17) = 46;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_11B460(&Src, "MAGZ");
  LOBYTE(v17) = 47;
  sub_14E2F0(&Src);
  LOBYTE(v17) = 12;
  if ( v16 >= 0x10 )
    operator delete(Src);
  sub_1950B0(a2, 128, &v10, 128, &v7);
  *(v3 + 632) = 0;
  QueryPerformanceFrequency(v3 + 73);
  LOBYTE(v17) = 11;
  if ( v7 )
  {
    std::_Container_base0::_Orphan_all(&v7);
    sub_137040(v7, v8);
    operator delete(v7);
    v7 = 0;
    v8 = 0;
    v9 = 0;
  }
  LOBYTE(v17) = 10;
  if ( v10 )
  {
    std::_Container_base0::_Orphan_all(&v10);
    sub_137040(v10, v11);
    operator delete(v10);
  }
  return v3;
}

Keep an eye on the LOBYTE, that is the corresponding byte we will be looking for, or in what order we will be receiving them... the first grouping is obviously the INSIGHT grouping.

warrenarea commented 7 years ago

as it only uses 5 sensors.

warrenarea commented 7 years ago

Think i also remember seeing a part of the code in what i referenced as being the Epoc+ data handler, which makes mention of 256, which is likely to handle the 256hz sample rate.

warrenarea commented 7 years ago

Also, the above function for the byte_names, my Epoc won't step into it... and I tried to see if it is something that is initialized at startup, and it doesn't seem to be... my guess, is it is waiting for the Epoc+ or Insight dongle to be attached to enter that function.

warrenarea commented 7 years ago

for those of you looking to read the code, x10 is obviously the LineFeed (Enter key) So when you see that, its checking to see if its at the end of the line, or in this case, the end of that specific data chunk.

ghost commented 7 years ago

Yeah I don't know we don't have that many bytes in a packet, maybe it's just initializing an array?

ghost commented 7 years ago

Unless it's concatenating the packets?