2013년 9월 12일 목요일

LINE(라인) protocol analysis [2] : HTTP(S) data


* 2014.08.02 update *

If you need a python code right away, then please keep in touch with https://github.com/carpedm20/LINE



Now, I decide to analyze the LINE protocol in more detail.

4. HTTP(S) Analysis



There are two particular headers, one is 'X-Line-Application' and the other is 'X-Line-Access'.

The first header, 'X-Line-Application', specify the kind of mobile phone, which is not that interesting one ;(

However, the second header 'X-Line-Access' seems like a session key and part of the key is encrypted by Base64.

I'll talk about this later :)

Anyway, after I decode the encrypted data, I can get 'iat: 1378973334524' (string data) and '��" [���<Z� � 5wxwO�' (byte[] data)

The format of POST data seems like 'bson' string which is used in LOCO protocol but it isn't.

To find out how the application deals with the session key and what kind of data type is used for POST data, I used .NET Reflector again and find out some interesting functions like send_sendMessage(int seq, Message message).


As you can see in this picture, there is a string "sendMessage" which also can be found in the POST data.

Therefore, I guess that this sendMessage function makes the POST data. 

I also figure out that WriteMessageBegin() and WriteMessageEnd() are the functions for Thrift platform.

I keep read some posts and decompiled codes to find out how Thrift works, but I can't figure out the exact structure of Thrift HTTP protocol.

  1. ## VERSION of Thrift protocol ##
  2. # TBinaryProtocol.VERSION_1 | type
  3. data = '\x80\x01\x00\x01'
  4. ## Function ##
  5. # \x00\x00\x00\x0b : sendMessage
  6. # \x00\x00\x00\x0f : fetchOperations, for read message
  7. data += '\x00\x00\x00\x0b' # length of function
  8. data += 'sendMessage'
  9. ## Message information for static message ##
    ## (not include sticker information) ##
  10. data += '\x00\x00\x00\x00'
  11. data += '\x08\x00\x01\x00'
  12. data += '\x00\x00\x00\x0c'
  13. data += '\x00\x02\x0b\x00'

  14. # \x01\x00\x00\x00 : from
  15. # \x02\x00\x00\x00 : to
  16. data += '\x02\x00\x00\x00' # to
  17. data += '????' # chat id to send message
  18. data += '\x0b\x00\x0a' # ChatId footer
  19. ## User input : not included in Thift protocol ##
  20. message = raw_input(">> ")
  21. ## Length of message ##
  22. #data += '\x00\x00\x00\x10' # \x06 : length
  23. data += struct.pack('>I',len(message))
  24. ## Message ##
  25. #for i in range(16):
  26. #    data += chr(49 + i) # 65 : A, 49 : 1
  27. data += message
  28. ## Message footer ##
  29. #data += '\x0a\x02\x00\x0e\x00\x00\x00'
  30. data += '\x02\x00\x0e\x00\x00\x00'

The bellow picture is the structure of Thrift packet based on the packet analysis that I took. (which may include some errors)

And the bellow code is a short python code which can be used to send message to someone (not me).

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. __author__ = 'carpedm20'
  4. import urllib2
  5. import struct
  6. url = 'http://gm.line.naver.jp/S3'
  7. headers = { 'POST' : '/S3',
  8.     'X-Line-Application' : 'WINPHONE.1.7.0.71.WindowsPhone.7.10.7720',
  9.     'Referer' : 'file:///Applications/Install/A18DAAA9-9A1C-4064-91DD-794644CD88E7/Install/',
  10.     'Accept-Encoding' : 'identity',
  11.     'Content-Type' : 'application/x-thrift',
  12.     'Accept' : 'application/x-thrift',
  13.     'X-Line-Access' : '????';
  14.     'Connection' : 'Keep-Alive',
  15.     'User-Agent' : 'WindowsPhone 1.7.0.71',
  16.     'HOST' : 'gm.line.naver.jp',
  17.     'Cache-Control' : 'no-cache'}
  18. def send():
  19.     data = '\x80\x01\x00\x01\x00\x00\x00\x0b'
  20.     data += 'sendMessage'
  21.     data += '\x00\x00\x00\x00\x08\x00\x01\x00\x00\x00\x00\x0c\x00\x02\x0b\x00\x02\x00\x00\x00'
  22.     data += '????' # chat id to send message
  23.     data += '\x0b\x00\x0a'
  24.     message = raw_input(">> ")
  25.     data += struct.pack('>I',len(message))
  26.     data += message
  27.     data += '\x02\x00\x0e\x00\x00\x00'
  28.     request = urllib2.Request(url, data, headers)
  29.     response = urllib2.urlopen(request)
  30.     print "[*] Result "
  31.     data = response.read()
  32.     for d in data:
  33.         print "%#x" % ord(d),
  34.     print
  35. def read():
  36.     data = '\x80\x01\x00\x01' # TBinaryProtocol.VERSION_1 | type
  37.     data += '\x00\x00\x00\x0f'
  38.     data += 'fetchOperations'
  39.     data += '\x00\x00\x00\x00\x0a'
  40.     data += '\x00\x02\x00\x00\x00\x00\x00\x00\x00\xf9\x08\x00\x03\x00\x00\x00\x14\x00'
  41.     request = urllib2.Request(url, data, headers)
  42.     response = urllib2.urlopen(request)
  43.     print "[*] Result "
  44.    
  45.     data = response.read()
  46.     for d in data:
  47.         print "%#x" % ord(d),
  48.     print
  49.     print data
  50. while 1:
  51.     send()

I can also figure out how to send an emoticon message through LINE.

I wish I can send some emoticons, which I have to buy to use them, but it doesn't worked with an error message "current user does not have this sticker" :(

ps. you can send some charged emoticons in LOCO protocol for nothing :)


Next : LINE protocol analysis [3] : session key

댓글 1개:

  1. Thanks for your great article about how LINE works.
    Besides, I'd like to ask a question that how to send image message. I've tried to use node.js to implement LINE API. However, when I want to send Image message, no matter I set the encoding of buffer to `binary` or `hex`, it still cannot show up the `contentPreview`. Do you know how to solve it or what the encoding is? Thanks a lot :)

    답글삭제