Need help understanding XOR cipher

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
2
down vote

favorite












I am trying to modify a save file for a game. I think it is using an XOR cipher to encrypt it. Looking though the disassembly I think I found the function that decrypts it. I ran the assembly through a decompiler to get a better grip on what is going on.



I am a C# programmer with some knowledge of C/C++. I generally understand what is accomplished by this code, but there are some details I don't understand.



int __fastcall DecryptBuffer(unsigned __int8 *a1, int a2, int a3, unsigned int a4, int a5)

unsigned __int8 *v5;
unsigned __int8 *v6;
int result;
int v8;

v5 = a1;
v6 = &a1[a2];
result = a5;
v8 = a5 - (_DWORD)v5;
while ( v5 != v6 )

result = *v5 ^ *(unsigned __int8 *)(a3 + (unsigned int)&v5[v8] % a4);
*v5++ = result;

return result;



It accepts as parameters:




  • a1 - a byte array


  • a2 - the length of the array


  • a3 - 0xB19D425B


  • a4 - 0x107


  • a5 - 0x00

First, I can't figure out the value of v8. I don't know what (_DWORD)v5 means, or why it is subtracted from zero.



Second, I don't know what (unsigned int)&v5[v8] is actually doing. I take it to mean it is looking up a byte somewhere in the array, but is it retrieving a single byte and casting to an uint, or four bytes?



Here is the disassembly:



sub_301E44
PUSH.W R4-R8,LR
MOV R4, R0
ADDS R6, R0, R1
LDR R0, [SP,#0x18+arg_0]
MOV R7, R2
MOV R8, R3
SUBS R5, R0, R4
loc_301E54
CMP R4, R6
BEQ locret_301E6C
ADDS R0, R5, R4
MOV R1, R8
BL.W __aeabi_uidivmod
LDRB R0, [R4]
LDRB R3, [R7,R1]
EORS R0, R3
STRB.W R0, [R4],#1
B loc_301E54
locret_301E6C
POP.W R4-R8,PC


This is the function that calls the above:



PUSH R0-R2,LR
MOVS R3, #0
LDR R2, =(dword_8749EF - 0x301E80)
STR R3, [SP,#0x10+var_10]
MOVW R3, #0x107
ADD R2, PC ; dword_8749EF
BL sub_301E44
ADD SP, SP, #0xC









share|improve this question









New contributor




Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.























    up vote
    2
    down vote

    favorite












    I am trying to modify a save file for a game. I think it is using an XOR cipher to encrypt it. Looking though the disassembly I think I found the function that decrypts it. I ran the assembly through a decompiler to get a better grip on what is going on.



    I am a C# programmer with some knowledge of C/C++. I generally understand what is accomplished by this code, but there are some details I don't understand.



    int __fastcall DecryptBuffer(unsigned __int8 *a1, int a2, int a3, unsigned int a4, int a5)

    unsigned __int8 *v5;
    unsigned __int8 *v6;
    int result;
    int v8;

    v5 = a1;
    v6 = &a1[a2];
    result = a5;
    v8 = a5 - (_DWORD)v5;
    while ( v5 != v6 )

    result = *v5 ^ *(unsigned __int8 *)(a3 + (unsigned int)&v5[v8] % a4);
    *v5++ = result;

    return result;



    It accepts as parameters:




    • a1 - a byte array


    • a2 - the length of the array


    • a3 - 0xB19D425B


    • a4 - 0x107


    • a5 - 0x00

    First, I can't figure out the value of v8. I don't know what (_DWORD)v5 means, or why it is subtracted from zero.



    Second, I don't know what (unsigned int)&v5[v8] is actually doing. I take it to mean it is looking up a byte somewhere in the array, but is it retrieving a single byte and casting to an uint, or four bytes?



    Here is the disassembly:



    sub_301E44
    PUSH.W R4-R8,LR
    MOV R4, R0
    ADDS R6, R0, R1
    LDR R0, [SP,#0x18+arg_0]
    MOV R7, R2
    MOV R8, R3
    SUBS R5, R0, R4
    loc_301E54
    CMP R4, R6
    BEQ locret_301E6C
    ADDS R0, R5, R4
    MOV R1, R8
    BL.W __aeabi_uidivmod
    LDRB R0, [R4]
    LDRB R3, [R7,R1]
    EORS R0, R3
    STRB.W R0, [R4],#1
    B loc_301E54
    locret_301E6C
    POP.W R4-R8,PC


    This is the function that calls the above:



    PUSH R0-R2,LR
    MOVS R3, #0
    LDR R2, =(dword_8749EF - 0x301E80)
    STR R3, [SP,#0x10+var_10]
    MOVW R3, #0x107
    ADD R2, PC ; dword_8749EF
    BL sub_301E44
    ADD SP, SP, #0xC









    share|improve this question









    New contributor




    Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





















      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I am trying to modify a save file for a game. I think it is using an XOR cipher to encrypt it. Looking though the disassembly I think I found the function that decrypts it. I ran the assembly through a decompiler to get a better grip on what is going on.



      I am a C# programmer with some knowledge of C/C++. I generally understand what is accomplished by this code, but there are some details I don't understand.



      int __fastcall DecryptBuffer(unsigned __int8 *a1, int a2, int a3, unsigned int a4, int a5)

      unsigned __int8 *v5;
      unsigned __int8 *v6;
      int result;
      int v8;

      v5 = a1;
      v6 = &a1[a2];
      result = a5;
      v8 = a5 - (_DWORD)v5;
      while ( v5 != v6 )

      result = *v5 ^ *(unsigned __int8 *)(a3 + (unsigned int)&v5[v8] % a4);
      *v5++ = result;

      return result;



      It accepts as parameters:




      • a1 - a byte array


      • a2 - the length of the array


      • a3 - 0xB19D425B


      • a4 - 0x107


      • a5 - 0x00

      First, I can't figure out the value of v8. I don't know what (_DWORD)v5 means, or why it is subtracted from zero.



      Second, I don't know what (unsigned int)&v5[v8] is actually doing. I take it to mean it is looking up a byte somewhere in the array, but is it retrieving a single byte and casting to an uint, or four bytes?



      Here is the disassembly:



      sub_301E44
      PUSH.W R4-R8,LR
      MOV R4, R0
      ADDS R6, R0, R1
      LDR R0, [SP,#0x18+arg_0]
      MOV R7, R2
      MOV R8, R3
      SUBS R5, R0, R4
      loc_301E54
      CMP R4, R6
      BEQ locret_301E6C
      ADDS R0, R5, R4
      MOV R1, R8
      BL.W __aeabi_uidivmod
      LDRB R0, [R4]
      LDRB R3, [R7,R1]
      EORS R0, R3
      STRB.W R0, [R4],#1
      B loc_301E54
      locret_301E6C
      POP.W R4-R8,PC


      This is the function that calls the above:



      PUSH R0-R2,LR
      MOVS R3, #0
      LDR R2, =(dword_8749EF - 0x301E80)
      STR R3, [SP,#0x10+var_10]
      MOVW R3, #0x107
      ADD R2, PC ; dword_8749EF
      BL sub_301E44
      ADD SP, SP, #0xC









      share|improve this question









      New contributor




      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      I am trying to modify a save file for a game. I think it is using an XOR cipher to encrypt it. Looking though the disassembly I think I found the function that decrypts it. I ran the assembly through a decompiler to get a better grip on what is going on.



      I am a C# programmer with some knowledge of C/C++. I generally understand what is accomplished by this code, but there are some details I don't understand.



      int __fastcall DecryptBuffer(unsigned __int8 *a1, int a2, int a3, unsigned int a4, int a5)

      unsigned __int8 *v5;
      unsigned __int8 *v6;
      int result;
      int v8;

      v5 = a1;
      v6 = &a1[a2];
      result = a5;
      v8 = a5 - (_DWORD)v5;
      while ( v5 != v6 )

      result = *v5 ^ *(unsigned __int8 *)(a3 + (unsigned int)&v5[v8] % a4);
      *v5++ = result;

      return result;



      It accepts as parameters:




      • a1 - a byte array


      • a2 - the length of the array


      • a3 - 0xB19D425B


      • a4 - 0x107


      • a5 - 0x00

      First, I can't figure out the value of v8. I don't know what (_DWORD)v5 means, or why it is subtracted from zero.



      Second, I don't know what (unsigned int)&v5[v8] is actually doing. I take it to mean it is looking up a byte somewhere in the array, but is it retrieving a single byte and casting to an uint, or four bytes?



      Here is the disassembly:



      sub_301E44
      PUSH.W R4-R8,LR
      MOV R4, R0
      ADDS R6, R0, R1
      LDR R0, [SP,#0x18+arg_0]
      MOV R7, R2
      MOV R8, R3
      SUBS R5, R0, R4
      loc_301E54
      CMP R4, R6
      BEQ locret_301E6C
      ADDS R0, R5, R4
      MOV R1, R8
      BL.W __aeabi_uidivmod
      LDRB R0, [R4]
      LDRB R3, [R7,R1]
      EORS R0, R3
      STRB.W R0, [R4],#1
      B loc_301E54
      locret_301E6C
      POP.W R4-R8,PC


      This is the function that calls the above:



      PUSH R0-R2,LR
      MOVS R3, #0
      LDR R2, =(dword_8749EF - 0x301E80)
      STR R3, [SP,#0x10+var_10]
      MOVW R3, #0x107
      ADD R2, PC ; dword_8749EF
      BL sub_301E44
      ADD SP, SP, #0xC






      c++ arm






      share|improve this question









      New contributor




      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 18 mins ago





















      New contributor




      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 4 hours ago









      Chet

      1135




      1135




      New contributor




      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Chet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          3
          down vote



          accepted










          (_DWORD)v5 is simply casting the __int8* pointer to _DWORD. Decompilations tend to be quite messy if you don't fix variable types, so let's ignore types for a moment.



          To understand the value of v8, substitute it into the expression bellow:
          &v5[a5 - v5_old]. We can also understand this as v5 + a5 - v5_old. v5 is being incremented with each iteration of the loop, so the above expression is basically the current index plus a5.



          The current index plus a5 modulo a4 (presumably the length of the buffer pointed to by a3) is then added to a3 and the corresponding byte is XOR'd to the byte currently pointed to by v5.



          Here's my take on the algorithm:



          void DecryptBuffer ( char *buffer, int buffer_len, char *key, int key_len, int key_start )

          int i;
          for ( i = 0; i < buffer_len; i++ )
          buffer [ i ] ^= key [ ( key_start + i ) % key_len ];



          Or in other words, XOR with the key repeating over and over.



          This is quite standard, so it's probably right, but it could be wrong—as I said, the decompilation is quite messy. If you want a sure answer, either clean it up by fixing variable types or post the disassembly as well.






          share|improve this answer




















          • Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
            – Chet
            16 mins ago










          Your Answer







          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "489"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          noCode: true, onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );






          Chet is a new contributor. Be nice, and check out our Code of Conduct.









           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19524%2fneed-help-understanding-xor-cipher%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          3
          down vote



          accepted










          (_DWORD)v5 is simply casting the __int8* pointer to _DWORD. Decompilations tend to be quite messy if you don't fix variable types, so let's ignore types for a moment.



          To understand the value of v8, substitute it into the expression bellow:
          &v5[a5 - v5_old]. We can also understand this as v5 + a5 - v5_old. v5 is being incremented with each iteration of the loop, so the above expression is basically the current index plus a5.



          The current index plus a5 modulo a4 (presumably the length of the buffer pointed to by a3) is then added to a3 and the corresponding byte is XOR'd to the byte currently pointed to by v5.



          Here's my take on the algorithm:



          void DecryptBuffer ( char *buffer, int buffer_len, char *key, int key_len, int key_start )

          int i;
          for ( i = 0; i < buffer_len; i++ )
          buffer [ i ] ^= key [ ( key_start + i ) % key_len ];



          Or in other words, XOR with the key repeating over and over.



          This is quite standard, so it's probably right, but it could be wrong—as I said, the decompilation is quite messy. If you want a sure answer, either clean it up by fixing variable types or post the disassembly as well.






          share|improve this answer




















          • Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
            – Chet
            16 mins ago














          up vote
          3
          down vote



          accepted










          (_DWORD)v5 is simply casting the __int8* pointer to _DWORD. Decompilations tend to be quite messy if you don't fix variable types, so let's ignore types for a moment.



          To understand the value of v8, substitute it into the expression bellow:
          &v5[a5 - v5_old]. We can also understand this as v5 + a5 - v5_old. v5 is being incremented with each iteration of the loop, so the above expression is basically the current index plus a5.



          The current index plus a5 modulo a4 (presumably the length of the buffer pointed to by a3) is then added to a3 and the corresponding byte is XOR'd to the byte currently pointed to by v5.



          Here's my take on the algorithm:



          void DecryptBuffer ( char *buffer, int buffer_len, char *key, int key_len, int key_start )

          int i;
          for ( i = 0; i < buffer_len; i++ )
          buffer [ i ] ^= key [ ( key_start + i ) % key_len ];



          Or in other words, XOR with the key repeating over and over.



          This is quite standard, so it's probably right, but it could be wrong—as I said, the decompilation is quite messy. If you want a sure answer, either clean it up by fixing variable types or post the disassembly as well.






          share|improve this answer




















          • Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
            – Chet
            16 mins ago












          up vote
          3
          down vote



          accepted







          up vote
          3
          down vote



          accepted






          (_DWORD)v5 is simply casting the __int8* pointer to _DWORD. Decompilations tend to be quite messy if you don't fix variable types, so let's ignore types for a moment.



          To understand the value of v8, substitute it into the expression bellow:
          &v5[a5 - v5_old]. We can also understand this as v5 + a5 - v5_old. v5 is being incremented with each iteration of the loop, so the above expression is basically the current index plus a5.



          The current index plus a5 modulo a4 (presumably the length of the buffer pointed to by a3) is then added to a3 and the corresponding byte is XOR'd to the byte currently pointed to by v5.



          Here's my take on the algorithm:



          void DecryptBuffer ( char *buffer, int buffer_len, char *key, int key_len, int key_start )

          int i;
          for ( i = 0; i < buffer_len; i++ )
          buffer [ i ] ^= key [ ( key_start + i ) % key_len ];



          Or in other words, XOR with the key repeating over and over.



          This is quite standard, so it's probably right, but it could be wrong—as I said, the decompilation is quite messy. If you want a sure answer, either clean it up by fixing variable types or post the disassembly as well.






          share|improve this answer












          (_DWORD)v5 is simply casting the __int8* pointer to _DWORD. Decompilations tend to be quite messy if you don't fix variable types, so let's ignore types for a moment.



          To understand the value of v8, substitute it into the expression bellow:
          &v5[a5 - v5_old]. We can also understand this as v5 + a5 - v5_old. v5 is being incremented with each iteration of the loop, so the above expression is basically the current index plus a5.



          The current index plus a5 modulo a4 (presumably the length of the buffer pointed to by a3) is then added to a3 and the corresponding byte is XOR'd to the byte currently pointed to by v5.



          Here's my take on the algorithm:



          void DecryptBuffer ( char *buffer, int buffer_len, char *key, int key_len, int key_start )

          int i;
          for ( i = 0; i < buffer_len; i++ )
          buffer [ i ] ^= key [ ( key_start + i ) % key_len ];



          Or in other words, XOR with the key repeating over and over.



          This is quite standard, so it's probably right, but it could be wrong—as I said, the decompilation is quite messy. If you want a sure answer, either clean it up by fixing variable types or post the disassembly as well.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 4 hours ago









          user2347953

          1213




          1213











          • Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
            – Chet
            16 mins ago
















          • Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
            – Chet
            16 mins ago















          Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
          – Chet
          16 mins ago




          Thanks so much, that works. I would never have realized that key was a pointer to an array (rather than just an integer) and that v8 was being used to determine how far into the buffer we were. I attached the disassembly for completeness.
          – Chet
          16 mins ago










          Chet is a new contributor. Be nice, and check out our Code of Conduct.









           

          draft saved


          draft discarded


















          Chet is a new contributor. Be nice, and check out our Code of Conduct.












          Chet is a new contributor. Be nice, and check out our Code of Conduct.











          Chet is a new contributor. Be nice, and check out our Code of Conduct.













           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19524%2fneed-help-understanding-xor-cipher%23new-answer', 'question_page');

          );

          Post as a guest













































































          Comments

          Popular posts from this blog

          Long meetings (6-7 hours a day): Being “babysat” by supervisor

          Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

          Confectionery