2013년 12월 4일 수요일

[python] Scrapy - 네이버 영화 파싱


Scrapy is a fast high-level screen scraping and web crawling framework, used to crawl websites and extract structured data from their pages. It can be used for a wide range of purposes, from data mining to monitoring and automated testing.

Scrapy documentation : http://doc.scrapy.org/en/0.20/


공식 페이지의 설명에서 볼 수 있듯이 Scrapy는 python 기반의 파싱 프레임워크다.

Scrapy를 알기 전에는 urllib2와 beatifulsoup로 파싱을 해 왔으나, Scrapy를 쓰면 훨씬 빠른 속도로 crawling을 할 수 있었다.


자세한 정보는 공식 튜토리얼을 통해서 얻을 수 있으며, Scrapy를 사용하기 위해서는 lxml, OpenSSL이 필요하다.

Installation : http://doc.scrapy.org/en/latest/intro/install.html

Tutorial : http://doc.scrapy.org/en/latest/intro/tutorial.html#crawling


간단하게 프로젝트를 시작하는 방법을 설명해 보면,

scrapy startproject scrapy_sample

cd scrapy_sample
vi scrapy_sample/spiders/spider.py
로 새로운 프로젝트를 하나 만들고, spider.py 파일을 만든다.


Scrapy 공식 홈페이지에 나와있는 example 소스는 아래와 같다.

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.item import Item, Field

class Website(Item): // parse 된 정보를 저장할 class
    name = Field() // Field()에는 숫자와 string 모두 저장할 수 있음
    description = Field()
    url = Field()

class DmozSpider(BaseSpider):
    name = "dmoz" // spider의 이름을 나타낸다
    allowed_domains = ["dmoz.org"] // dmoz.org 이외의 redirect는 무시된다.
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/",
    ] // start_urls 안에 들어있는 url이 parse 된다

    def parse(self, response):
        hxs = HtmlXPathSelector(response)

        // css selector 문법을 통해 dom element 를 찾을 수 있다.
        sites = hxs.select('//ul[@class="directory-url"]/li') 
        items = []

        for site in sites:
            item = Website()
            item['name'] = site.select('a/text()').extract()
            item['url'] = site.select('a/@href').extract()
            item['description'] = site.select('text()').re('-\s([^\n]*?)\\n')
            items.append(item)
            
        return items

이후 project 의 root 디렉토리에서 아래와 같은 명령어를 입력하면 된다.

scrapy crwal dmoz // spiders 폴더 내에 있는 소스 코드 중 dmoz를 이름으로 가지고 있는 spider를 실행
scrapy crawl dmoz -o some.json -t json 2> result.txt // item을 json형태로 txt 파일에 저장
 
rm result.txt // 크롤 하기 전에 result.txt는 매번 지워주어야 함
 
scrapy shell spider.py // scrapy를 shell 형태로 실행
scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"

selector 에 대한 정보는

http://doc.scrapy.org/en/latest/topics/selectors.html

여기서 찾을 수 있다.


Scrapy에 대한 한국어 문서가 없어서 제대로된 사용법을 찾는데 시간이 조금 걸렸지만,

다른분들은 이 글을 읽으시고 시간낭비를 하지 않으시길 바란다.


아래의 예제는 네이버 영화 정보를 파싱하는 spider다.

영화 제목과 개봉시기, 장르 등의 정보를 파싱하며 위에 나온 명령어들을 사용하면 쉽게 json 파일을 얻을 수 있을 것이다.


__author__ = 'carpedm20'
__date__ = '2013.11.14'

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.http.request import Request
from scrapy.item import Item, Field

import sys, os

class ScrapyItem(Item):
    title = Field()
    url = Field()
    year = Field()
    open1 = Field() # 2013
    open2 = Field() # 06.12
    country = Field()
    genre = Field()
    form = Field()
    grade = Field()

YEAR = "2015"
START_PAGE = 10 # 0
START_PAGE = 0 # 0
MAX_LOOP = 4 #-1
MAX_LOOP = -1 #-1
PMOD = True
PMOD = False

print "==================="
print YEAR
print "==================="

url = "http://movie.naver.com/movie/sdb/browsing/bmovie.nhn?year="+YEAR+"&page=" + str(START_PAGE)

index = start_page = START_PAGE
old_index = -1
old_title = ""
loop = 0
pmod = PMOD
max_loop = MAX_LOOP

class ScrapyOrgSpider(BaseSpider):
    name = "naver"
    allowed_domains = ["movie.naver.com"]
    start_urls = [url]

    def parse(self, response):
        global start_page, index, loop, old_title, pmod, max_loop

        hxs = HtmlXPathSelector(response)
        items = []

        loop += 1

        next_page = ["http://movie.naver.com/movie/sdb/browsing/bmovie.nhn?year="+YEAR+"&page="+str(loop + start_page)]

        if max_loop != -1:
          if loop >= max_loop:
              next_page = []

        posts = hxs.select("//ul[@class='directory_list']/li")
        title = posts[0].select("a/text()")[0].extract()

        if old_title == title and loop > 2:
          next_page = []
        else:
          old_title = title

        if not not next_page:
            yield Request(next_page[0], self.parse)

        #posts = hxs.select("//tr")

        count = 0
        print "[ " + str(loop) + " ] index : " + str(index) + ", len(posts) : " + str(len(posts))

        for post in posts:
            try:
              title = post.select("a/text()")[0].extract()
              if pmod: print " [ " + str(count) + " ] TITLE : " + title
              url = post.select("a/@href")[0].extract()
              if pmod: print " [ " + str(count) + " ] URL : " + url
              year = post.select("ul[@class='detail']/li/a")[0].select("b/text()")[0].extract()
              if pmod: print " [ " + str(count) + " ] YEAR : " + year

              open1 = ""
              open2 = ""
              country = ""
              genre = ""
              form = ""
              grade = ""

              open_count = 0
              lis = post.select("ul[@class='detail']/li/a")

              for li in lis:
                h = li.select('@href')[0].extract()
                href = h[h.find('&')+1:h.rfind('=')]
                if pmod: print " [*] HREF : " + href

                if href == '?year':
                  if pmod: print "  [-] HREF SKIP : " + h
                  continue

                if href == 'open' and open_count == 0:
                  open1 = li.select('text()')[0].extract()
                  open_count += 1
                  if pmod: print " [*] open1 : " + open1
                elif  href == 'open' and open_count == 1:
                  try:
                    open2 = li.select('text()')[0].extract()
                    if pmod: print " [*] open2 : " + open2
                  except:
                    z = 123
                elif href == 'nation':
                  country = li.select('text()')[0].extract()
                  if pmod: print " [*] country : " + country
                elif href == 'genre':
                  genre = li.select('text()')[0].extract()
                  if pmod: print " [*] genre : " + genre
                elif href == 'form':
                  form = li.select('text()')[0].extract()
                  if pmod: print " [*] form : " + form
                elif href == 'grade':
                  grade = li.select('text()')[0].extract()
                  if pmod: print " [*] grade : " + grade
                else:
                  print " [^] Found NEW href : " + h
                  return

              count += 1
            except Exception as e:
              #for frame in traceback.extract_tb(sys.exc_info()[2]):
              #  fname,lineno,fn,text = frame
              #  print "Error in %s on line %d" % (fname, lineno)
              exc_type, exc_obj, exc_tb = sys.exc_info()
              fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
              print(exc_type, fname, exc_tb.tb_lineno)
              #for e in sys.exc_info():
              #  print e
              continue

            item = ScrapyItem()
            item["title"] = title
            item["url"] = url
            item["year"] = year
            item["open1"] = open1
            item["open2"] = open2
            item["country"] = country
            item["genre"] = genre
            item["form"] = form
            item["grade"] = grade
            items.append(item)

        for item in items:
            yield item

        old_index = index
        index += count

ps.


2013년 12월 3일 화요일

왓챠 (Watcha) api 분석


왓챠는 유저의 평가를 바탕으로 영화를 추천해주는 웹 서비스다.

왓챠를 분석하게 된 이유는 유한개의 DB를 가지고 있는 서비스에서

모든 영화를 평가했을때 어떻게 될까 라는 단순한 호기심이 생겼었기 때문이다.

사실 웹 사이트 api 분석이라기 보다는 json 둘러보기 정도가 더 정확한듯 하다.


MySQL을 사용하고는 있으나 웹 프레임 워크(루비온레일즈)를 사용하고 있기 때문에 sql injection를 기대하진 않았다.

또한 왓챠의 멤버 중에서 보안 실력이 뛰어난 분이 계시기 때문에 큰 문제는 없을거란걸 알았다.


가장 핵심인 '영화 추천' 부분은 무한 스크롤 기능을 통해 서버에 request를

http://watcha.net/api/movies/recommend?ref=wall&count=8&more=true

와 같은 주소로 전송하고 json 형태로 받아오게 된다.



count를 증가시키면 데이터를 더 받아올 수는 있지만 위의 request로는 20개가 최대인것 같다.

하지만

http://watcha.net/api/movies?type=eval&count=900&more=true&page=

와 같은 형태로 request를 보내면 900개의 데이터를 볼 수 있었다.




그리고 구글링을 통해서

http://watcha.net/movies/detail/18681‎

와 같은 형태로 영화 정보를 얻을 수 있다는 사실을 알 수 있었다.

이를 통해 watcha에 저장된 모든 영화의 id와 hash된 id를 얻을 수 있었다.


다행이도 지금은 위의 url이 막힌것처럼 보이며,

http://watcha.net/api/movie/mp0dx6

와 같이 숫자가 아닌 hash화된 id를 통해서 영화 정보를 얻어온다.


그리고 비슷한 영화를 추천할 때는

http://watcha.net/api/movies/similar/mvf3t1?count=10

와 같은 request를 보내게 된다.


영화 검색시에는

http://watcha.net/search.json?query=%20&page=1

와 같이 request를 보내며 javascript 로 공백을 검색하는것을 막아 뒀지만,


http://watcha.net/search.json?query=+ 와 같은 형태로 우회할 수 있다.


그래서 watcha가 가지고 있는 영화 DB의 갯수가 대략 6만개 정도라고 예상했다.


네이버의 DB가 약 9만개인 점을 생각한다면 적다고 생각했지만, 네이버와 달리

드라마 정보가 적기 때문이라고 생각했다.


대충 소스를 짜서 돌려본 결과 아래와 같은 계정을 만들 수 있었고,


무한 로딩


추천하는 영화가 없음


위와 같이 평소에 보지 못했던 새로운 메세지를 볼 수 있었다 :)

( 하지만 페이지 로딩 시간은 상당히 길어졌다 )


쿼리를 바꿔보면 새로운 쿼리를 찾을 수 도 있을것 같지만, 호기심은 해결되었으니 더 둘러보지는 않았다.


나는 이 글을 통해 왓챠가 보안에 취약하다는 것을 말하려고 하는 것은 아니다.

단지, 평소에 즐겨 쓰던 서비스였기 때문에 애정이 많이 가지만,

DB가 생각했던것보다 많이 공개되어 있어서 조금 조심할 필요가 있다고 생각된다.


사실 웹 개발에 대한 지식이 부족해서 어떻게 개선할 수 있을지는 잘 모르겠다..


마지막으로 다른분들은 이런 잉여짓을 하지 않기를 바란다...

[Python] Twitter hacking


The title is somewhat attractive but I'm not (maybe can't) going to talk about hacking the Twitter server.

As you know, Twitter is a well known social network and lots of people use Twitter openly and share his or others information through Twitter.

But some people use their account privately, which means they use Twitter to communicate with his friends.

These people tends to make mistake like twit his personal information on Twitter.




So, I want to show you how easily people can be hacked through Twitter.

I took this experiment few months ago and I could get 1560 different phone numbers in one week...


DO NOT USE THIS FOR REAL HACKING!

Just be careful when you use SNS or internet.


  1. # -*- coding:utf-8 -*-
  2. import time
  3. from twitter import *
  4. import re
  5. import MySQLdb
  6. DB_NAME = 'twitter'
  7. DB_TABLE = 'phone'
  8. # tid bigint(20), name varchar(20), text text, number bigint(20)
  9. DB_ID = 'carpedm20'
  10. DB_PASS = ' '
  11. db = MySQLdb.connect(host="", user=DB_ID, db=DB_NAME, passwd=DB_PASS, port=3306)
  12. cur = db.cursor()
  13. OAUTH_TOKEN = ''
  14. OAUTH_SECRET = ''
  15. CONSUMER_KEY = ''
  16. CONSUMER_SECRET = ''
  17. = Twitter( auth=OAuth(OAUTH_TOKEN, OAUTH_SECRETCONSUMER_KEY, CONSUMER_SECRET)
  18. findNum = re.compile(r'regular expression for phone number')
  19. while 1:
  20.         print "= start at " + time.ctime() + " ="
  21.         output = t.search.tweets(q="010",lang='ko',count='100')
  22.         print output['search_metadata']['count']
  23.         for s in output['statuses']:
  24.                 tid =  s['id']
  25.                 name = s['user']['name'].encode('utf-8')
  26.                 text = s['text'].replace("'","").encode('utf-8')
  27.                 number = findNum.findall(s['text'])
  28.                 upload_time = s['created_at'].encode('utf-8')
  29.                 if number is []:
  30.                         continue
  31.                 query = "SELECT * FROM "+DB_TABLE+" WHERE tid="+str(tid)
  32.                 cur.execute(query)
  33.                 if cur.fetchone() != None:
  34.                         continue
  35.                 for n in number:
  36.                         query = "INSERT INTO "+DB_TABLE+" (`tid`,`name`,`text`,`number`,`time`) VALUES("+str(tid)+",'"+name+"','"+text+"','"+str(n)+"','"+upload_time+"');"
  37.                         print query
  38.                         try:
  39.                                 cur.execute(query)
  40.                                 db.commit()
  41.                         except:
  42.                                 print "ERROR : " + query
  43.         time.sleep(30)

2013년 12월 2일 월요일

컴공아 일하자 (Comgong Job)

Comgong Job


What is Comgong Job

This is a python code for Comgong Job bot.
This is a program that uploads newest internship and recruit announcements to facebook automatically.

Links

Copyright

Copyright (c) 2013 Kim Tae Hoon

Screenshots


* 2015.04.17 *



* 2014.05.31 *



* 2013.12.05 *


2013년 11월 29일 금요일

무비덕 (MovieDuk)

MovieDuk



What is MovieDuk


Enjoy your Movies, movieduks!
ps. code is really dirty, because this was my first Django project...

Author


  • Kim Tae Hoon, blog.

Copyright (c) 2013 Kim Tae Hoon

Screenshot












[Python] 포탈봇




This is a python code for UNIST portal bot.
Portal bot is a program that uploads the UNIST's portal announcements to facebook automatically.

Facebook : https://www.facebook.com/hexa.portal

github : https://github.com/carpedm20/UNIST-portal-bot

Mailing list : http://portalbot.us.to

Copyright (c) 2013 Kim Tae Hoon

2013년 11월 1일 금요일

[Network] 패킷 분석

====================
 Wireshark
====================


0. Stream filter

tcp.stream eq 14

1. Protocol filter

snmp || dns || icmp || http

* SNMP(Simple Network Management Protocol) : 네트워크 장비를 관리 감시하기 위한 목적, 네트워크 관리자가 네트워크 성능을 관리하고 네트워크 문제점을 찾아 수정하는데 도움
* DNS(Domain Name System) :  도메인 이름을 호스트의 네트워크 주소로 바꾸거나 그 반대의 변환을 수행할 수 있도록 하기 위해 개발
* icmp(Internet Control Message ProtocolInternet Control Message Protocol) : 네트워크 컴퓨터 위에서 돌아가는 운영체제에서 오류 메시지를 전송받는 데 주로 쓰임

2. IP filter

ip.addr == 10.1.1.1 (Source & Destination)

ip.src != 10.1.2.3 or ip.dst != 10.4.5.6
ip.dst == 10.36.115.40
ip.src != 10.1.2.3 and ip.dst != 10.4.5.6

ip.addr==174.137.42.75 and ip.addr==10.36.115.40 (to look up the conversation)

4. Port filter

tcp.port == 25 (Source & Destination)
tcp.dstport == 25
tcp.srcport == 80
tcp.flags

4. TCP filter

tcp.flags.syn : 세션을 설정하는 데에 사용되며 초기에 시퀀스 번호를 보냄
tcp.flags.ack :

5. Search

http.host contains google

ctrl + f > string search -> packet list, packet details, packet bytes
ctrl + n > next search
ctrl + b > previous search

----------------------------------------

1. File > Export Objects > HTTP

http 소스, 이미지 등의 파일 리소스 추출

2. Content -Encoding: gzip

.gz 으로 저장해서 압축을 풀어 확인    

3. File > Export Specified packet > 하단 Packet Range 에서 Displayed 선택 후 저장

필터링 된 패킷을 다시 분석하고 싶을때


====================
 Malzilla
====================

1. Misc Decoders > USC2 To Hex

유니코드를 hex로 변환

2. Hex View -> 악성 javascript 분석

string to find : http 

Key : bd (xor)


====================
 NetworkMiner
====================



호스트 리스트를 한눈에 볼 수 있고, 파일이나 이미지 목록을 바로 받아볼 수 있는 장점

필터를 자유롭게 걸 수 없다는 단점


====================
 TCP
====================

1. 방화벽으로 인해서 해당 페이지에 접근은 차단

- 3 Way hand shake -

서비스 port 가 열려 있을 경우 SYN+ACK 패킷 회신 후 ACK 를 전송

서비스 port 가 닫혀 있는 경우 RST+ACK 패킷을 회신



Wireshark에서는 RST ACK 이 빨간색으로 나타남

RST ACK 만 확인하고 싶으면 tcp.flags.reset ==1 로 필터링



[Android] smali 디컴파일


.method로 시작하여 .end method

.method private 함수 이름(파라미터 데이터 타입; ; ;) 리턴 값

[ : array[] 의미

[Ljava/lang/String : String[]
Ljava/math/BigInteger : BigInteger


  1. ==== Example 1 ====
  2. .method private isValid([Ljava/lang/String;[Ljava/lang/String;Ljava/math/BigInteger;)Ljava/lang/Boolean;
  3.     .locals 7 // 메소드 내부에서 사용하는 레지스터 수 ex. v1~v7
  4.     .parameter "issuerDN" // 파라미터 이름, 뒤에서부터, p3
  5.     .parameter "subjectDN" // p2
  6.     .parameter "serial" // p1      
  7. .prologue
  8.     const/4 v6, 0x4 // v6 = 0x4
  9.     const/4 v5, 0x3 // v5 = 0x3
  10.     const/4 v4, 0x2 // v4 = 0x2
  11.     const/4 v3, 0x1 // v3 = 0x1
  12.     const/4 v2, 0x0 // v2 = 0x0
  13. .line 103
  14.     aget-object v0, p1v2   // v0 = p1[v2],  v0 = serial[v2]array[] (p1)의 특정 index(v2) 의 값을 v0에 저장
  15.     // p0 는 this 인듯...
  16.     iget-object v1, p0Lops/black/herpderper/TrustModifier$AlwaysTrustManager;->CN1:Ljava/lang/String; // v1 = this.AlwaysTrustManager->C1
  17.     invoke-virtual {v0, v1}Ljava/lang/String;->equals(Ljava/lang/Object;)Z // v0 = String->equals(v0v1);
  18.     move-result v0
  19.     if-eqz v0, :cond_0 // v0가 0 이면 cond_0 로 점프
  20.     aget-object v0, p1v3
  21.     iget-object v1, p0Lops/black/herpderper/TrustModifier$AlwaysTrustManager;->OU:Ljava/lang/String; // AlwaysTrustManager->OU
  22.     invoke-virtual {v0, v1}Ljava/lang/String;->equals(Ljava/lang/Object;)Z
  23.     move-result v0
  24.     if-eqz v0, :cond_0 // if(v0 == 0) goto cond_0;
  25.     ...
  26.     .line 119
  27.     invoke-static {v3}Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean; //  v0 = Boolean->valueOf(v3);
  28.     move-result-object v0
  29.     .line 121
  30.     :goto_0
  31.     return-object v0 // return v0;
  32.     :cond_0
  33.     invoke-static {v2}Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;  // v0 = Boolean->valueOf(v2); // v2=0=false
  34.     move-result-object v0
  35.     goto :goto_0
  36. ==== Result 1 ====
  37. private Boolean isValid(String[] serial, String[] subjectDN, BigInteger issuerDN) {
  38.   v6=4;
  39.   v5=3;
  40.   v4=2;
  41.   v3=1;
  42.   v2=0;
  43.   v0 = serial[v2];
  44.   v1 = AlwaysTrustManager->C1;
  45.   v0 = String->equals(v0v1);
  46.   if(v0 == 0)
  47.      goto cond_0;
  48.   v0 = serial[v3];
  49.   v1 = AlwaysTrustManager->OU;
  50.   v0 = String->equals(v0v1);
  51.   if(v0 == 0)
  52.      goto cond_0;
  53.   ...
  54.   v0 = Boolean->valueOf(v3); // v3=1=true
  55.   :goto_0
  56.   return v0;
  57.   :cond_0
  58.   v0 = Boolean->valueOf(v2); // v2=0=false
  59.   goto: goto_0;
  60. ==== Example 2 ====
  61. # virtual methods
  62. .method protected varargs doInBackground([Ljava/lang/String;)Ljava/lang/String;
  63.     .locals 17
  64.     .parameter "uri"
  65.     .prologue
  66.     .line 28
  67.     invoke-static {}Landroid/os/Debug;->isDebuggerConnected()Z
  68.     move-result v14
  69.     if-eqz v14, :cond_0
  70.     .line 29
  71.     const/16 v14, 0x539
  72.     div-int/lit8 v14, v140x0
  73.     .line 31
  74.     :cond_0
  75.     const/4 v11, 0x0
  76.     .line 34
  77.     .local v11, url:Ljava/net/URL;
  78.     :try_start_0
  79.     new-instance v12, Ljava/net/URL;
  80.     const/4 v14, 0x0
  81.     aget-object v14, p1v14
  82.     invoke-direct {v12, v14}Ljava/net/URL;-><init>(Ljava/lang/String;)V // <init>() 괄호 안에 변수 갯수 = 파라미터 갯수, 즉 v14만 파라미터 v12 는 리턴값 저장
  83.     :try_end_0
  84.     .catch Ljava/net/MalformedURLException{:try_start_0 .. :try_end_0} :catch_1
  85.     .end local v11           #url:Ljava/net/URL; // 이런건 다 코멘트
  86.     .local v12, url:Ljava/net/URL;
  87.     move-object v11, v12
  88.     .line 41
  89.     .end local v12           #url:Ljava/net/URL;
  90.     .restart local v11       #url:Ljava/net/URL;
  91.     :goto_0
  92.     const/4 v13, 0x0
  93.     .line 44
  94.     .local v13, urlConnection:Ljava/net/HttpURLConnection;
  95.     :try_start_1
  96.     invoke-virtual {v11}Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
  97.     move-result-object v14
  98.     move-object v0, v14
  99.     check-cast v0, Ljava/net/HttpURLConnection;
  100.     move-object v13, v0
  101.     .line 47
  102.     const/4 v14, 0x1
  103.     invoke-virtual {v13, v14}Ljava/net/HttpURLConnection;->setDoOutput(Z)V // Z -> 하나의 파라미터 나타냄, v13.HttpURLConnection->setDoOutput(v14);
  104.     .line 48
  105.     const-string v14, "POST"
  106.     invoke-virtual {v13, v14}Ljava/net/HttpURLConnection;->setRequestMethod(Ljava/lang/String;)V
  107.     .line 51
  108.     invoke-static {v13}Lops/black/herpderper/TrustModifier;->relaxHostChecking(Ljava/net/HttpURLConnection;)V
  109.     .line 52
  110.     invoke-virtual {v13}Ljava/net/HttpURLConnection;->getOutputStream()Ljava/io/OutputStream;
  111.     move-result-object v5
  112.     .line 55
  113.     .local v5, out:Ljava/io/OutputStream; // v5 = get_OutputStream();
  114.     const/4 v14, 0x1
  115.     aget-object v14, p1v14
  116.     const-string v15, "UTF-8"
  117.     ...
  118.   :catch_1
  119.     move-exception v1
  120.     .line 38
  121.     .local v1, e1:Ljava/net/MalformedURLException;
  122.     invoke-virtual {v1}Ljava/net/MalformedURLException;->printStackTrace()V
  123.     goto/16 :goto_0
  124. ==== Result 2 ====
  125. protected String doInBackground(String[] uri) {
  126.   v14 = android.os.Debug.isDebuggerConnected();
  127.   if(v14==0)
  128.     goto cond_0;
  129.   v14 = 0x539;
  130.   v14 = v14 / 0;
  131.   :cond_0
  132.   v11 = 0;
  133.   v11 = url:Ljava/net/URL;
  134.   :try_start_0
  135.   v12 = java/net/URL;
  136.   v14 = 0;
  137.   v14 = uri[v14]; // v14 = uri[0];
  138.   v12 = URL->init(v14);
  139.   :try_end_0
  140.   .catch MalformedURLException :catch_1
  141.   v11 = (java/net/URL) v12;
  142.   :goto_0
  143.    v13 = 0;
  144.    v13 = (HttpURLConnection) v13;
  145.   :try_start_1
  146.    v14 = URL->openConnection(v11);
  147.    v0 = v14;
  148.    v0 = (HttpURLConnection) v0;
  149.    v13 = v0;
  150.    v14 = 1;
  151.    v13.setDoOutput(v14);
  152.    v14 = "POST";
  153.    v13.setRequestMethod(v14);
  154.    ops.black.herpderper.TrustModifier.relaxHostChecking(v13);
  155.    v5 = getOutputStream(v13);
  156.    v14 = 1;
  157.    v14 = uri[v14];