'분류 전체보기' 카테고리의 글 목록 (2 Page) :: YPrefer's Develop&Security

Fasoo Web DRM 을 사용해서, 웹사이트의 오른쪽 버튼과 스크린샷 방지를 하고 있는 웹사이트들이 있다

웹 DRM은 해당 웹페이지에 접근시, Response로 Fasoo를 활성화 시키는 script를 내려 주는데

Froxy Tool을 이용해 이 script를 삭제 해주면, 오른쪽 버튼과 스크린샷 등이 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
 
document.write("<object id=WebDM style=display:none classid=clsid:4FEBA4F2-1906-44BB-B269-7B5A4AE8CC6D><param name="wmode" value="transparent" /></object>");
document.write("<object id=f_swv style=display:none classid=clsid:30A39E90-1C8A-4EA4-8733-8C3DD0818281><param name="wmode" value="transparent" /></object>");
document.write("<meta http-equiv=imagetoolbar content=no>");
 
function GoError(win, errNo)
{
 win.location.href = strErrUrl+"?errNo="+errNo;
 return;
}
 
</script>

 

네이버 블로그 등에서도 마찬가지로 우클릭 우회가 가능한데,

IE에서는 개발자 도구(F12)를 이용해서 사용안함 탭에서 javascript를 체크

크롬에서는 개발자 도구(Ctrl+Shitft+I) 를 이용해서 설정에서 javascript 사용안함에 체크

로 쉽게 우회할 수 있다.

 

'Security > Etc' 카테고리의 다른 글

WannaCry Ransomware Scanner  (0) 2017.10.27
[경험공유] Android DB 파일 암호화 :)  (0) 2016.06.07
[경험공유] Android 데이터 암호화 :)  (0) 2016.06.03
[경험공유] Firmware 분석 :)  (0) 2016.06.03
[경험공유] Dexprotector :(  (0) 2016.06.01

2016/05/31 -  [Security/Android] - [Android APK 진단] 1. 툴 소개 - 추가 16.06.07

2016/06/07 - [Security/Android] - [Android APK 진단] 2. DIVA. 앱 로그 확인하기 1, 하드코딩된 중요정보 확인하기 1

2016/06/07 - [Security/Android] - [Android APK 진단] 3. DIVA. 안전하지 않은 데이터 저장 확인하기 1

2016/06/07 - [Security/Android] - [Android APK 진단] 4. DIVA. 안전하지 않은 데이터 저장 확인하기 2

 

7. Input Validation Issues - Part 1

유저이름으로 정보를 검색하는 화면이다.

Hint 를 보면 세유저의 정보가 데이터베이스에 있고 그중에 하나는 admin으로 주어져 있다.

 

처음에 어떤 화면이 저 소스코드인지 몰라서 메인 화면을 보니까 SQL injection 액티비티인것을 확인했다.

 

소스를 확인하니까 database를 만들고 세 유저의 정보를 넣는 부분을 확인할 수 있다.

 

보통 SQL injection은 웹해킹시에 쓰이지만, android에서도 db를 만들수 있으니 sql injection공격도 가능하다.

아래와 같이 조건문이 무조건 참이 되도록 만들어주면, 모든 정보를 긁어 올 수 있도록 할 수 있다.

 

※ 필자의 경험공유 - 필자는 SQL injection 의 경우는 웹 해킹에서만 경험해 보았다.

웹 해킹에서는 sqlmap이라는 sqlinjection 점검 도구를 사용할 수 있는데, 이 Tool이 문제를 종종 일으켜서 같은 url에

같은 파라미터를 대상으로 시도했어도 결과가 다른 결과가 나오기도 해서 python으로 간단한 sqlinjection을 시도하는 스크립트를 만들기도 했었다.

 

8. Input Validation Issues - Part 2

하단에 URL을 입력하는 화면이 나온다.

 

소스코드를 확인해보면 입력한 구문이 webview의 url로 들어가는 것을 확인할 수 있다.

 

file:// 프로토콜을 이용해 단말의 데이터에 접근할 수 있는데, 현재는 nox 에뮬레이터(ROOT권한을 가짐)으로 shell로 확인할 수 있지만,

루팅되지 않은 단말의 경우 권한 에러가 뜨면서 shell에서는 접근이 불가능하다.

 

2016/05/31 -  [Security/Android] - [Android APK 진단] 1. 툴 소개 - 추가 16.06.07

2016/06/07 - [Security/Android] - [Android APK 진단] 2. DIVA. 앱 로그 확인하기 1, 하드코딩된 중요정보 확인하기 1

2016/06/07 - [Security/Android] - [Android APK 진단] 3. DIVA. 안전하지 않은 데이터 저장 확인하기 1

 

5. Insecure Data Storage - Part3

화면을 보면 아이디와 패스워드를 입력하는 부분이 나온다. 

아이디와 패스워드 등의 중요정보를 넣고 저장 버튼을 누르면 저장이 성공적으로 완료 되었다는 Toast를 볼수 있다.

 

코드를 확인해 보면 이번엔 로그인 패스워드와 아이디를 file로 만드는 것을 알 수 있다.

만들어진 temp 파일은 apk 설치 디렉토리 하단에 생성되고 확인해보면 아이디와 패스워드가 저장되있는 것을 볼 수 있다.

 

※ 필자의 경험공유 - 점검을 했던 앱중에 하나는 파일을 미리보기 할 수 만 있고, 보안정책상 다운로드나 캡쳐는 불가능 했었다.

그런데, 파일 미리보기 할 때 임시파일을 만들어둬서 이것을 중간에 빼낼 수 있었던 사례가 있다.

 

 

6. Insecure Data Storage - Part 4

화면을 보면 아이디와 패스워드를 입력하는 부분이 나온다. 

아이디와 패스워드 등의 중요정보를 넣고 저장 버튼을 누르면 저장이 성공적으로 완료 되었다는 Toast를 볼수 있다.

 

코드를 확인하면 외부저장장치아래에 숨김파일로 uinfo.txt를 만들어 아이디와 패스워드를 저장하는 것을 볼 수 있다.

 

find 명령을 사용해 해당 파일의 위치를 찾아 확인하면 아래와 같이 아이디와 패스워드를 얻을 수 있다.

find 명령을 설명하면,

/ : 루트 디렉토리 하단에

-name "*uinfo.txt*" : uinfo.txt가 파일명에 들어있는 것을 검색한다.

2>/dev/null : 검색 중 not permitted 등 에러메세지는 출력하지 않는다.

 

 

 

2016/05/31 -  [Security/Android] - [Android APK 진단] 1. 툴 소개 - 추가 16.06.07

2016/06/07 - [Security/Android] - [Android APK 진단] 2. DIVA. 앱 로그 확인하기 1, 하드코딩된 중요정보 확인하기 1

 

 

3. Insecure Data Storage - Part 1

화면을 보면 아이디와 패스워드를 입력하는 부분이 나온다. 

아이디와 패스워드 등의 중요정보를 넣고 저장 버튼을 누르면 저장이 성공적으로 완료 되었다는 Toast를 볼수 있다.

 

해당 액티비티의 코드를 확인해보면, Preference에 user와 password정보를 저장하는 것을 알 수 있다.

 

find / -name "*앱이름*" 2>/dev/null 명령을 통해 해당 앱이 설치된 디렉토리를 알아내고, (/data/data/패키지명/ 에 설치가 된다.)

하위 디렉토리중 shared_prefs 에 들어가 저장된 xml을 확인해보면 아래와 같이 user와 password가 저장되는 경우를 볼 수 있다.

보통 자동로그인을 구현하기위해 아이디와 패스워드를 preference에 저장해두는데, 평문으로 저장되는 경우도 있고, 암호화를 해서 저장하는 경우도

존재한다.

 

필자의 경험공유 -  1. 암호화를 하기는 하지만 암호화 키가 소스코드에 박혀있는 경우

2. 아이디의 암호화 로직과 패스워드의 암호화 로직이 같아 암호화된 패스워드를 아이디 부분에 덮어씌우면 앱을 실행시에 로그인을 위해 복호화를 하면서 패스워드가 보이는 경우

3. preference의 암호화키가 단말마다 다르지 않아, xml 파일 자체를 빼내어 다른 단말에 넣어 로그인이 가능했던 경우

 

4. Insecure Data Storage - Part 2

화면을 보면 아이디와 패스워드를 입력하는 부분이 나온다. 

아이디와 패스워드 등의 중요정보를 넣고 저장 버튼을 누르면 저장이 성공적으로 완료 되었다는 Toast를 볼수 있다.

 

역시 소스를 확인해보면 DB에 Insert를 하는 것을 알수 있다.

 

위에서와 같이 설치된 경로밑의 databases폴더에 들어가면, ids2라는 파일이 보이는데, 이 파일을

adb pull /data/data/jakhar.aseem.diva/databases/ids2 명령을 통해 끄집어 낸다

 

끄집어낸 db파일은 sqllitebrowser를 통해 읽을 수 있다.

 

※ 필자의 경험공유 - 2016/06/07 - [Security/Etc] - 경험공유 - Android DB 파일 암호화 :)

 

전에 안드로이드 앱 점검을 하던 중 db파일을 추출해내서 데이터를 확인하려고 한 적이 있었다.

근데, 이게 분명 db파일임은 파일명에서 부터 D!B! 라고 적혀 있어서 확신할 수 있는데, Sqlbrowser을 통해 열리지가 않는 거였다.


심증은 있지만 물증이 없어 확인을 못하던 상황!

혹시나 해서 Hex Editor로 열어보니, 일반적인 DB파일은 Header가 SQL...뭐 이렇게 시작되어야 하는데,

이상한 값으로 적혀있는 걸보고 이상하다 싶어서 hex 값들을 쭉보고 있는데

보통은 00으로 섹션이 나누어지는데 이상하게 77이라는 값이 무지 많이 보였었다.

 

(정상적인 db파일)

 


 

여기서 XOR 연산을 했구나 싶어 malzilla를 이용해 XOR 키를 찾았더니 77을 키로 xor 연산을 한 걸 알 수 있었다.

링크 : http://malzilla.sourceforge.net/


키를 알고 그걸로 다시 복호화를 시도하니 정상적인 db파일로 떨어져서, DB내용을 볼 수 있었다.


오래 되서 잘 기억은 나지 않지만, 암호화 키를 77로 하지 않고 앱의 패스코드와 모바일의 유니크값을

섞은 것을 키로 사용하는 것으로 수정했던 것으로 기억한다.

2016/05/31 -  [Security/Android] - [Android APK 진단] 1. 툴 소개 - 추가 16.06.07


루팅된 안드로이드 단말에 대상 APK 를 설치하고,실행하면 아래와 같은 화면이 출력된다

 

 

 

1. INSECURE LOGGING

여기서 첫번째 안전하지 않은 로그를 살펴보자

보면, 문자열을 입력하고 check out을 누르면, Toast가 하나 뜨는것을 볼수 있는데, 이 화면에서는 입력한 문자열을 중요정보라고 가정하였다.

 

필자는 nox_adb를 이용해 shell에 들어왔고, 단말을 사용하면 adb shell을 이용하면 된다.

logcat 명령어를 통해 현재 디바이스의 로그를 출력하는데, 앱 패키지 명인 diva로 필터를 걸어 출력하면 아래와 같은 로그를 볼 수 있다.

아래에 credit card정보인 1234가 로그에 평문으로 찍히는 것을 볼 수 있다.

 

※ 필자의 경험 공유 - 세션 아이디나 아이디 패스워드 등을 출력하는 경우,

함수전달할때의 파라미터, Response 등을 로그로 출력하는 등의 경우가 있는데 이러한 정보는 직접적으로 사용되거나 공격자에게 정보를 줌으로써 다른 방법과 섞여 사용될 수 있다.

 

 

 

 

2. Hardcoding Issues - Part 1

아래 화면을 보면 key 값을 입력하고, ACCESS버튼을 누르면 접근이 제한되었다는 토스트가 나오고 있다.

JADX를 통해 소스코드를 분석해보면(DIVA난독화가 적용되어 있지 않지만, 설사 적용되어있더라도 일정부분 분석이 가능하다).

단순히 입력 문자열을 비교하는 것을 확인할 수 있고, 이를 통해 하드코딩된 key값을 얻어낼 수 있다.

 

하드코딩된 키 값을 입력하면 아래와 같이 접근이 허용되었다는 Toast가 출력된다.

 

※ 필자의 경험 공유 - 2016/06/03 - [Security/Etc] - 경험공유 - Android 데이터 암호화 :)

 

필자는 LG U+ VIP 인데, 이 등급인 사람에게는 한달에 2회 영화를 무료로!(물론 한명만 대상이 된다.)

볼 수 있는 혜텍이 주어진다.

 

 


 

그런데 예매가 오직 LG U+ 홈페이지. 그것도 데스크탑 환경에서만 가능하고, 영화 상영 1시간 전까지만 가능하다.

상영 1시간 이내에는 아래와 같이 예매 버튼이 비활성화 되어 클릭할수 없게 되는데,.

 

 

개발자 도구를 이용하면 이를 우회 가능하다.

즉, 1시간 이내 상영 영화라도 예매가 가능하다는 것이다..!

개발자 도구의 DOM 탐색기 에서 아래의 네모위에 커서 있는 버튼을 클릭하여

비활성화 된 영화를 클릭하여 확인해보면, 아래와 같이 class=soldout으로 되어있는 것을 볼수 있다.

 

오른쪽 버튼을 눌러 편집으로, class soldout 을 지워준다.

이렇게 해주는 것만으로도 아래와 같이 비활성화가 풀리면서 클릭이 가능해진다.

 

 

이를 통해 영화 예매가 정상적으로 가능해지는데,

이는 체크로직이 서버에 있는 것이 아니라 클라이언트의 자바스크립트에 있기 때문이다.

 

LG입장에서는 이것이 중요하지 않은 체크로직이라 생각해서 클라이언트에 맡겨놓은 것이겠지만,

이렇게 간단한 우회를 통해 개발자가 의도하지 않은 행동을 할 수 있다,.

 

이와 같이 클라이언트에서의 체크로직은 쉽게 우회가 가능하기 때문에,

암호화 (단방향암호화),  패스워드 체크로직 등이 클라이언트에서 이루어지는지 웹점검시에 확인해보아야 한다.


'Security > Web' 카테고리의 다른 글

[Web 진단] XSS 공격 시나리오 & 진단방법  (2) 2016.11.28

점검한 앱중에 중요한 데이터를 단말에 저장하는 앱이 있었다.

개발자와 인터뷰를 통해 단말에 저장되는 데이터는 어떻게 관리가 되는지 물었더니 

특별한 방법을 사용해서 볼 수 없도록 만들었다 라는 자신감 넘치는 대답을 들었다.


링크 : https://www.eldos.com/solfs/

어떻게 했는지 코드를 분석하여 확인해보니 solfs라는 가상 스토리지를 사용하는 것으로 보여졌고,

이 스토리지를 이용하는데 필요한 패스워드는 하드코딩 되어있었다.


패스워드는 알고 있으니 보는 방법을 구글링 해봤는데, Solfs Explorer란 것이 있었고

이 프로그램을 구하기 위해 반나절을 족히 썻다.


결국 설치 파일을 구해서 설치하고 패스워드 넣으니

자신감 있었던게 무색하게 허무하게 데이터를 열람 할 수 있었다.

필자가 경험한 펌웨어 분석경험을 흐름대로 정리한 것이다.

어떤 제품인지는 보안상 적을 수 없지만, 이런 식으로 한다는 느낌적인 느낌을 남겨놓으려고 정리한다.


펌웨어 분석

<!--[if !supportLists]-->    <!--[endif]-->펌웨어 파일을 확인할 수 있는 도구 : Firmware mod kit, binwalk

펌웨어를 웹에서 다운받거나, Flash memory에서 덤프하는 방법으로 얻어낸다. 필자의 경우 점검이라 제공을 받았다.

Root:~#Binwalk –e rootfs2.2.0release를 하면 cramfs파일이 나오고,

cramfs 7zip으로 풀리기도 하고 mount-t type cramfs로 마운트하여 내용을 확인할 수 도 있다.

, firmware mode kit의 기능중에 uncram하는 기능이 있어 이를 통해 확인할 수 도 있다.

이렇게 나온 cramfs파일은 Root:~#file cramfs하면, Linux Compressed Rom File System data인인 것을 확인할 수 있다.

풀린 파일의 etc/shadow파일을 확인하면 hdd에 링크되어 있는 것을 확인할 수 있고,

Hdd를 풀기위해 타입을 확인해야 하는데 etc/fstab을 확인하면, 타입을 yaffs2타입인 것을 확인할 수 있다.

Hdd.2.8.2.release unyaffbinwalk로 풀면 shadow file의 내용을 확인할 수 있고, john the ripper를 이용해 root 의 패스워드를 얻을 수 있다.

<!--[if !supportLists]-->    <!--[endif]-->Nmap을 이용해 월 패드를 포트스캔하여 현재 서비스중인 포트들을 확인하고펌웨어의 바이너리 파일중 bind, listen, accept등 소켓통신시 사용되는 함수를 쓰는 바이너리 파일을 찾는다.

이 바이너리 파일들을 IDA를 이용해 리버싱 하여, 포트에 맞는 바이너리 파일을 찾아낸다.

그중 펌웨어 업데이트를 수행하는 바이너리를 찾아내고 업데이트 서버의 id/pwd를 알게 되면, 

telnet을 서비스하게 변조한 펌웨어로 업로드하는 명령을 내려, telnet을 서비스하도록 만들어 외부에서 접속이 가능하다.

 

 ARM환경구축

<!--[if !supportLists]-->    <!--[endif]-->구축에 사용한 도구 : QEMU, gdb, strace, ida

QEMU 에뮬레이터를 이용해 ARM OS를 올릴 수 있어 동적 디버깅을 시도해볼 수 있다.

https://people.debian.org/~aurel32/qemu/armel/ 에서 qemu를 다운받아 실행하고, proxy setting을 해주어 apt-get으로 update 

build-essential, gdb, strace를 설치한다.

qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4versatile -initrd initrd.img-3.20-4-versatile -hda debian_wheezy_armel_standard.qcow2 -append "root=/dev/sda1" -redir tcp:2222::22

위와 같이 qemu를 실행하면 2222번 포트로 qemu ssh서비스를 붙을수 있어 scp로 파일전송이 용이하다.

<!--[if !supportLists]-->    <!--[endif]-->lsdaemon프로그램을 qemu로 옮기고, ldd를 이용해 ASLR이 적용된 OS라면

sysctl -w kernel.randomize_va_space=0를 적어 ASLR기능을 끄고, strace로 확인하면 관련라이브러리가 없음을 알수 있고, 관련라이브러리를 펌웨어에서 찾아 넣어주고 없는 파일을 touch로 빈파일을 만들어준다.

그러면 정상실행이 되지만 app_init에서 죽는 것을 확인할 수 있는데, 이것을 확인하기 위해, gdb로 따라가서 확인하면 daemon(0,0)에서 죽는 것을 알 수 있고 이 부분의 코드를 NOP으로 코드패치를 한다.

ld --verbose ./lsdaemon | grep SEGMENT_START 를 실행하면 baseaddress를 얻어낼 수 있다.

이를 통해 ida에서 edit->segment->rebaseprogram에서 baseaddress를 설정해주면,

실행 중인 주소와, ida의 주소값을 맞춰줄 수 있다.

이때 코드패치는 IDA hexview에서 F2를 누르고 apply를 해주면, 코드패치가 된다. 코드패치된 파일을 다시 넣어주고 실행하면 hostname을 불러오는 곳에서 죽고, hostname을 펌웨어의 것과 맞추어 주어 실행하고, strace로 에러를 제거해주는 방법을 반복해서 구축하여 동적디버깅을 실시한다

필자의 회사의 경우 보안을 위해 외부 인터넷 망과 연결시 Proxy를 통해야 한다.

그런데, 보안점검을 하다보면 Proxy를 Burpsuite나 Fiddler와 같은 Tool의 포트로 변경해줘야 하는 일이 있는데,

이걸 매번 브라우저의 설정탭을 찾아 들어가 변경하기도 귀찮고,

그렇다고 Cooxie Toolbar같은걸 번거롭게 설치해서 마우스 클릭질 하는 것도 맘에 들지 않아서, Java로 변경해주는 걸 하나 만들어 보았다.


이 방법은 Java를 이용해 Registery 값을 수정하는 방법인데, Chrome과 IE는 적용되지만 FireFox는 따로 Proxy 정보를 저장하고 있어 적용되지 않는다.


소스를 보면, 간단하다.

Proxy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package oneclickproxy;
 
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
import javax.swing.JDialog;
import javax.swing.JOptionPane;
 
import ca.beq.util.win32.registry.RegistryKey;
import ca.beq.util.win32.registry.RegistryValue;
import ca.beq.util.win32.registry.RootKey;
import ca.beq.util.win32.registry.ValueType;
import oneclickproxy.WinInet.INTERNET_PER_CONN_OPTION_LIST;
public class proxy {
 
    private static final String REGEDIT_KEY = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
    private static final String PROXY_VALUE = "ProxyEnable";
    private static final String AUTOCONFIG_VALUE = "AutoConfigURL";
    private static final String PROXYOVERRIDE_VALUE = "ProxyOverride";
    private static final String PROXYSERVER_VALUE = "ProxyServer";
    private static final String REGISTRY_LIBRARY_PATH = "\\lib\\jRegistryKey.dll";
    private static final String CONFIG_FILEPATH = "\\dat\\config.dat";
     
    static INTERNET_PER_CONN_OPTION_LIST list = new INTERNET_PER_CONN_OPTION_LIST();
     
    public static void main(String[] args) {
        // Load JNI library
//      System.out.println(System.getProperty("java.library.path"));
//      System.out.println(new File(".").getAbsolutePath()+REGISTRY_LIBRARY_PATH);
        RegistryKey.initialize(new File(".").getAbsolutePath()
                + REGISTRY_LIBRARY_PATH);
 
        proxy proxy = new proxy();
        int before = proxy.getProxyEnable(); // 0 :: enable 1 :: able
        int after = before;
        System.out.println("before :: " + before);
        do {
            proxy.setconfigurl(before);
            after = proxy.setProxyEnable(before);
            System.out.println("mid :: " + after);
        } while (before == after);
        System.out.println("after :: " + after);
 
        JOptionPane op = new JOptionPane(after == 0 ? "���Ͻü�����\n��Ȱ��ȭ�Ǿ����ϴ�."
                : "���Ͻü�����\nȰ��ȭ�Ǿ����ϴ�.", after == 0 ? JOptionPane.ERROR_MESSAGE
                : JOptionPane.INFORMATION_MESSAGE);
        WinInet.INSTANCE.InternetSetOption(null,
                WinInet.INTERNET_OPTION_PER_CONNECTION_OPTION, null, 0);
        WinInet.INSTANCE.InternetSetOption(null,
                WinInet.INTERNET_OPTION_SETTINGS_CHANGED, null, 0);
        WinInet.INSTANCE.InternetSetOption(null,
                WinInet.INTERNET_OPTION_REFRESH, null, 0);
        RegistryKey.initialize(new File(".").getAbsolutePath()
                + REGISTRY_LIBRARY_PATH);
        final JDialog dialog = op.createDialog("OCP 1.4 made by Y.S.H");
        dialog.setAlwaysOnTop(true); // <-- this line
 
        ScheduledExecutorService sch = Executors.newSingleThreadScheduledExecutor();    
        sch.schedule(new Runnable() {
            public void run() {
                dialog.setVisible(false);
                dialog.dispose();
            }
        }, Integer.parseInt(proxy.get_specificline(3,
                new File(".").getAbsolutePath() + CONFIG_FILEPATH)), TimeUnit.MILLISECONDS);
         
        dialog.setVisible(true);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.addWindowListener(new WindowAdapter() {
            @Override public void windowClosed(WindowEvent e) {
              System.exit(0);
            }
          });
        System.exit(0);
    }
 
    private void setconfigurl(int a) {
        // TODO Auto-generated method stub
        RegistryKey key = new RegistryKey(RootKey.HKEY_CURRENT_USER,
                REGEDIT_KEY);
        if (a == 0) {
            if (key.hasValue(AUTOCONFIG_VALUE))
                key.deleteValue(AUTOCONFIG_VALUE);
        } else {
            System.out.println(get_specificline(0,
                    new File(".").getAbsolutePath() + CONFIG_FILEPATH));
            RegistryValue value = new RegistryValue(AUTOCONFIG_VALUE,
                    ValueType.REG_SZ, get_specificline(0,
                            new File(".").getAbsolutePath() + CONFIG_FILEPATH));
            key.setValue(value);
        }
        RegistryValue server_value = new RegistryValue();
        server_value.setName(PROXYSERVER_VALUE);
        server_value.setType(ValueType.REG_SZ);
        server_value.setData(get_specificline(1,
                new File(".").getAbsolutePath() + CONFIG_FILEPATH));
        if (key.hasValue(PROXYSERVER_VALUE)) {
            key.setValue(server_value);
        }
        RegistryValue override_value = new RegistryValue();
        override_value.setName(PROXYOVERRIDE_VALUE);
        override_value.setType(ValueType.REG_SZ);
        override_value.setData(get_specificline(2,
                new File(".").getAbsolutePath() + CONFIG_FILEPATH));
 
        if (key.hasValue(PROXYOVERRIDE_VALUE)) {
            key.setValue(override_value);
        }
    }
 
    private int getProxyEnable() {
        RegistryKey key = new RegistryKey(RootKey.HKEY_CURRENT_USER,
                REGEDIT_KEY);
        RegistryValue value = key.getValue(PROXY_VALUE);
 
        if (key.hasValue(PROXY_VALUE)) {
            return Integer.parseInt(value.getData().toString());
        }
        return 0;
    }
 
    private int setProxyEnable(int enable) {
        RegistryKey key = new RegistryKey(RootKey.HKEY_CURRENT_USER,
                REGEDIT_KEY);
        RegistryValue value = new RegistryValue();
        value.setName(PROXY_VALUE);
        value.setType(ValueType.REG_DWORD_BIG_ENDIAN);
        int after = enable == 0 ? 1 : 0;
        value.setData(after);
 
        if (key.hasValue(PROXY_VALUE)) {
            key.setValue(value);
        }
        return after;
    }
 
    public String get_specificline(int lineNumber, String filename) {
        try {
            FileInputStream fs = new FileInputStream(filename);
            BufferedReader br = new BufferedReader(new InputStreamReader(fs));
            for (int i = 0; i < lineNumber; ++i) {
                br.readLine();
            }
            return br.readLine();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "FAIL";
    }
}


WinInet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
package oneclickproxy;
 
import java.util.Arrays;
import java.util.List;
 
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Union;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
 
public interface WinInet extends StdCallLibrary {
    WinInet INSTANCE = (WinInet) Native.loadLibrary("wininet", WinInet.class,
            W32APIOptions.UNICODE_OPTIONS);
 
    public static final int INTERNET_PER_CONN_FLAGS = 1;
    public static final int INTERNET_PER_CONN_PROXY_SERVER = 2;
    public static final int INTERNET_PER_CONN_PROXY_BYPASS = 3;
    public static final int INTERNET_PER_CONN_AUTOCONFIG_URL = 4;
    public static final int INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5;
    public static final int INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6;
    public static final int INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7;
    public static final int INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8;
    public static final int INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9;
 
    public static final int PROXY_TYPE_DIRECT = 0x00000001; // direct to net
    public static final int PROXY_TYPE_PROXY = 0x00000002; // via named proxy
    public static final int PROXY_TYPE_AUTO_PROXY_URL = 0x00000004; // autoproxy
                                                                    // URL
    public static final int PROXY_TYPE_AUTO_DETECT = 0x00000008; // use
                                                                    // autoproxy
                                                                    // detection
 
    //
    // options manifests for Internet{Query|Set}Option
    //
 
    public static final int INTERNET_OPTION_CALLBACK = 1;
    public static final int INTERNET_OPTION_CONNECT_TIMEOUT = 2;
    public static final int INTERNET_OPTION_CONNECT_RETRIES = 3;
    public static final int INTERNET_OPTION_CONNECT_BACKOFF = 4;
    public static final int INTERNET_OPTION_SEND_TIMEOUT = 5;
    public static final int INTERNET_OPTION_CONTROL_SEND_TIMEOUT = INTERNET_OPTION_SEND_TIMEOUT;
    public static final int INTERNET_OPTION_RECEIVE_TIMEOUT = 6;
    public static final int INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT = INTERNET_OPTION_RECEIVE_TIMEOUT;
    public static final int INTERNET_OPTION_DATA_SEND_TIMEOUT = 7;
    public static final int INTERNET_OPTION_DATA_RECEIVE_TIMEOUT = 8;
    public static final int INTERNET_OPTION_HANDLE_TYPE = 9;
    public static final int INTERNET_OPTION_LISTEN_TIMEOUT = 11;
    public static final int INTERNET_OPTION_READ_BUFFER_SIZE = 12;
    public static final int INTERNET_OPTION_WRITE_BUFFER_SIZE = 13;
 
    public static final int INTERNET_OPTION_ASYNC_ID = 15;
    public static final int INTERNET_OPTION_ASYNC_PRIORITY = 16;
 
    public static final int INTERNET_OPTION_PARENT_HANDLE = 21;
    public static final int INTERNET_OPTION_KEEP_CONNECTION = 22;
    public static final int INTERNET_OPTION_REQUEST_FLAGS = 23;
    public static final int INTERNET_OPTION_EXTENDED_ERROR = 24;
 
    public static final int INTERNET_OPTION_OFFLINE_MODE = 26;
    public static final int INTERNET_OPTION_CACHE_STREAM_HANDLE = 27;
    public static final int INTERNET_OPTION_USERNAME = 28;
    public static final int INTERNET_OPTION_PASSWORD = 29;
    public static final int INTERNET_OPTION_ASYNC = 30;
    public static final int INTERNET_OPTION_SECURITY_FLAGS = 31;
    public static final int INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT = 32;
    public static final int INTERNET_OPTION_DATAFILE_NAME = 33;
    public static final int INTERNET_OPTION_URL = 34;
    public static final int INTERNET_OPTION_SECURITY_CERTIFICATE = 35;
    public static final int INTERNET_OPTION_SECURITY_KEY_BITNESS = 36;
    public static final int INTERNET_OPTION_REFRESH = 37;
    public static final int INTERNET_OPTION_PROXY = 38;
    public static final int INTERNET_OPTION_SETTINGS_CHANGED = 39;
    public static final int INTERNET_OPTION_VERSION = 40;
    public static final int INTERNET_OPTION_USER_AGENT = 41;
    public static final int INTERNET_OPTION_END_BROWSER_SESSION = 42;
    public static final int INTERNET_OPTION_PROXY_USERNAME = 43;
    public static final int INTERNET_OPTION_PROXY_PASSWORD = 44;
    public static final int INTERNET_OPTION_CONTEXT_VALUE = 45;
    public static final int INTERNET_OPTION_CONNECT_LIMIT = 46;
    public static final int INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT = 47;
    public static final int INTERNET_OPTION_POLICY = 48;
    public static final int INTERNET_OPTION_DISCONNECTED_TIMEOUT = 49;
    public static final int INTERNET_OPTION_CONNECTED_STATE = 50;
    public static final int INTERNET_OPTION_IDLE_STATE = 51;
    public static final int INTERNET_OPTION_OFFLINE_SEMANTICS = 52;
    public static final int INTERNET_OPTION_SECONDARY_CACHE_KEY = 53;
    public static final int INTERNET_OPTION_CALLBACK_FILTER = 54;
    public static final int INTERNET_OPTION_CONNECT_TIME = 55;
    public static final int INTERNET_OPTION_SEND_THROUGHPUT = 56;
    public static final int INTERNET_OPTION_RECEIVE_THROUGHPUT = 57;
    public static final int INTERNET_OPTION_REQUEST_PRIORITY = 58;
    public static final int INTERNET_OPTION_HTTP_VERSION = 59;
    public static final int INTERNET_OPTION_RESET_URLCACHE_SESSION = 60;
    public static final int INTERNET_OPTION_ERROR_MASK = 62;
    public static final int INTERNET_OPTION_FROM_CACHE_TIMEOUT = 63;
    public static final int INTERNET_OPTION_BYPASS_EDITED_ENTRY = 64;
    public static final int INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO = 67;
    public static final int INTERNET_OPTION_CODEPAGE = 68;
    public static final int INTERNET_OPTION_CACHE_TIMESTAMPS = 69;
    public static final int INTERNET_OPTION_DISABLE_AUTODIAL = 70;
    public static final int INTERNET_OPTION_MAX_CONNS_PER_SERVER = 73;
    public static final int INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER = 74;
    public static final int INTERNET_OPTION_PER_CONNECTION_OPTION = 75;
    public static final int INTERNET_OPTION_DIGEST_AUTH_UNLOAD = 76;
    public static final int INTERNET_OPTION_IGNORE_OFFLINE = 77;
    public static final int INTERNET_OPTION_IDENTITY = 78;
    public static final int INTERNET_OPTION_REMOVE_IDENTITY = 79;
    public static final int INTERNET_OPTION_ALTER_IDENTITY = 80;
    public static final int INTERNET_OPTION_SUPPRESS_BEHAVIOR = 81;
    public static final int INTERNET_OPTION_AUTODIAL_MODE = 82;
    public static final int INTERNET_OPTION_AUTODIAL_CONNECTION = 83;
    public static final int INTERNET_OPTION_CLIENT_CERT_CONTEXT = 84;
    public static final int INTERNET_OPTION_AUTH_FLAGS = 85;
    public static final int INTERNET_OPTION_COOKIES_3RD_PARTY = 86;
    public static final int INTERNET_OPTION_DISABLE_PASSPORT_AUTH = 87;
    public static final int INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY = 88;
    public static final int INTERNET_OPTION_EXEMPT_CONNECTION_LIMIT = 89;
    public static final int INTERNET_OPTION_ENABLE_PASSPORT_AUTH = 90;
 
    public static final int INTERNET_OPTION_HIBERNATE_INACTIVE_WORKER_THREADS = 91;
    public static final int INTERNET_OPTION_ACTIVATE_WORKER_THREADS = 92;
    public static final int INTERNET_OPTION_RESTORE_WORKER_THREAD_DEFAULTS = 93;
    public static final int INTERNET_OPTION_SOCKET_SEND_BUFFER_LENGTH = 94;
    public static final int INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95;
 
    public static final int INTERNET_OPTION_DATAFILE_EXT = 96;
 
    // BOOL InternetSetOption(
    // _In_ HINTERNET hInternet,
    // _In_ DWORD dwOption,
    // _In_ LPVOID lpBuffer,
    // _In_ DWORD dwBufferLength
    // );
    public boolean InternetSetOption(Pointer hInternet, int dwOption,
            Pointer lpBuffer, int dwBufferLength);
 
    // typedef struct _FILETIME {
    // DWORD dwLowDateTime;
    // DWORD dwHighDateTime;
    // } FILETIME, *PFILETIME;
    public static class FILETIME extends Structure {
        public static class ByReference extends FILETIME implements
                Structure.ByReference {
            public ByReference() {
            }
 
            public ByReference(Pointer memory) {
                super(memory);
            }
        }
 
        public FILETIME() {
        }
 
        public FILETIME(Pointer memory) {
            super(memory);
            read();
        }
 
        public int dwLowDateTime;
        public int dwHighDateTime;
 
        @SuppressWarnings("rawtypes")
        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[] { "dwLowDateTime",
                    "dwHighDateTime" });
        }
    }
 
    // typedef struct {
    // DWORD dwOption;
    // union {
    // DWORD dwValue;
    // LPTSTR pszValue;
    // FILETIME ftValue;
    // } Value;
    // } INTERNET_PER_CONN_OPTION, *LPINTERNET_PER_CONN_OPTION;
    public static class INTERNET_PER_CONN_OPTION extends Structure {
        public static class ByReference extends INTERNET_PER_CONN_OPTION
                implements Structure.ByReference {
            public ByReference() {
            }
 
            public ByReference(Pointer memory) {
                super(memory);
            }
        }
 
        public INTERNET_PER_CONN_OPTION() {
        }
 
        public INTERNET_PER_CONN_OPTION(Pointer memory) {
            super(memory);
            read();
        }
 
        public static class VALUE_UNION extends Union {
            public int dwValue;
            public String pszValue;
            public FILETIME ftValue;
        }
 
        public int dwOption;
        public VALUE_UNION Value = new VALUE_UNION();
 
        @SuppressWarnings("rawtypes")
        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[] { "dwOption", "Value" });
        }
    }
 
    // typedef struct {
    // DWORD dwSize;
    // LPTSTR pszConnection;
    // DWORD dwOptionCount;
    // DWORD dwOptionError;
    // LPINTERNET_PER_CONN_OPTION pOptions;
    // } INTERNET_PER_CONN_OPTION_LIST, *LPINTERNET_PER_CONN_OPTION_LIST;
    public static class INTERNET_PER_CONN_OPTION_LIST extends Structure {
        public static class ByReference extends INTERNET_PER_CONN_OPTION_LIST
                implements Structure.ByReference {
            public ByReference() {
            }
 
            public ByReference(Pointer memory) {
                super(memory);
            }
        }
 
        public INTERNET_PER_CONN_OPTION_LIST() {
        }
 
        public INTERNET_PER_CONN_OPTION_LIST(Pointer memory) {
            super(memory);
            read();
        }
 
        public int dwSize;
        public String pszConnection;
        public int dwOptionCount;
        public int dwOptionError;
        public INTERNET_PER_CONN_OPTION.ByReference pOptions;
 
        @SuppressWarnings("rawtypes")
        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[] { "dwSize", "pszConnection",
                    "dwOptionCount", "dwOptionError", "pOptions" });
        }
    }
}



이 소스는 java에서 registery값에 접근하는 jRegistryKey라는 라이브러리를 사용한다.

그 라이브러리를 이용하기위한 Interface가 WinInet.java이고, 실제 동작하는건 Proxy.java라고 보면 된다.

링크 : https://sourceforge.net/projects/jregistrykey/

라이브러리 사용하는 방법은 일반적이니 따로 적지 않겠다.


설명하자면, Windows의 Proxy 설정값은 Registery의 CURRENT_USER의 Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings

밑에 위치하게 되고 여기에서 프록시 설정에 대한 값들이 있는데,

ProxyEnable : 현재 프록시가 켜져있는지 아닌지의 값.  0 또는 1

ProxyServer : 프록시 서버 주소

ProxyOverride : 프록시 주소를 사용하지 않는 예외 주소들

AutoConfigURL : 프록시 자동구성 스크립트 주소

이다.


이 값을 이용해 현재 프록시가 켜져 있다면 꺼주고, 꺼져 있다면 같은 폴더의 dat폴더 밑 config.dat파일을 참조하여 값을 읽어와 그 설정과 같이

Proxy 설정을 해준다.

config.dat파일의 첫번째 라인을 자동구성 스크립트에, 두번째라인은 프록시 주소에, 세번째 라인은 예외 주소, 네번째 라인은 다이어로그가 실행되는 시간(1000이 1초) 로 구성된다.


이렇게 만들어진 프로그램을 바로가기로 만들어 우측버튼의 속성을 통해 바로가기키를 지정해두면 단축키로 프록시 활성/비활성화가 가능해진다.


만들어진 Tool로 손쉽게 프록시 활성/비활성화를 하면서 홈페이지을 조지면 된다!

+ Recent posts