반응형

XP에서 visual studio 2008 을 이용하여 OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid) 실패!!

이거 왜이랫!!  간단한거 사람 또 헤메이게 만든다 ㅡㅡ;; 

디버그 모드에서는 프로세스 핸들을 자알~~ 얻어온다. 빌드하고 실행하면 실패한다.

줴길슨~ 욕 나올수밖에 없다. 이건 뭐 어떻게 문제인지 알수조차 없넹 디버그모드는 되는데

빌드후에 안나온다. ㅡㅡ; 끙끙.. 병이 걸리기 시작한다. 두통이 온다.

MSDN에서 권한 찾아본다. 스샷 짠하고 남겨봅니다.


구글링으로 좀 더 찾아보니 권한 중에 MAXIMUM_ALLOWED 이 있다.

최대한으로 권한을 허락한다는 뜻인거 같은데.. 이걸 사용하니 잘 된다. ㅡㅡ;

OpenProcess(MAXIMUM_ALLOWED,FALSE,pid)    이렇게 하니 잘 됩니다.

관련 자료를 찾아보려 했으나 왜 이렇게 해야 되는지 자세히 나와있는 자료가 없는거 같네요.

오랫만에 C계열 프로그램 해보니 모르는 것도 많고 재밌네요..


반응형


VIsual Studio 2008로 Console 프로그램을 만들어 봤다.

주로 JAVA 프로그래밍을 하다가 C계열을 하다보니 툴도 손에 익지 않고 영 감이 부족하다.

MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup

나를 반기는 error 메시지 이거 뭐지.. 끙끙대며.. 캐삽질 中..中..中..中.....

해결방법은 프로젝트 속성에 설정만 해주면 된다.

(프로젝트 선택하고 오른쪽 클릭 properties 클릭!)

Configuration Properties -> Linker -> System -> SubSystem 에서 

Console (/SUBSYSTEM:CONSOLE) 으로 설정을 바꿔주자.. 띠리리

1>XXXXXXX - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 1 up-to-date, 0 skipped ==========

에러 처리 완료!! 이런 캐삽질 ㅎㅎ;

반응형
error C2664: 'XXXXXXXXW' : cannot convert parameter 1 from 'const char [13]' to 'LPCWSTR'

error C2664: 'XXXXXXXXW' : cannot convert parameter 2 from 'const char [13]' to 'LPCWSTR'

이것도 뭐 글을 길게 쓰고 싶지 않은 에러상황이다. 유니코드 관련 error 인데..

다른방법도 여러개 찾았지만 가장 적합한 방법은 Project properties를 설정하는 것!!

간단하게 방법만 남기고 넘어가자.. 피곤하다 캐삽질 짜잉나!!!!

프로젝트 선택하고 오른쪽 클릭 properties 클릭!)



스샷으로 대충 때우려 했지만 스샷으로 어디지 헷갈릴수도 있으니

Configuration Properties -> Generall -> Project Defaults -> Character Set   에 보면

Use Unicode Character Set  또는 Use Multi-Byte Character Set 라면 과감히 Not Set 선택하자!!

error Clear!!!  아 글 쓰는것도 힘들구나.. 좀더 신중히 글을 작성해야하지만 핵심만 간단히^^;
반응형
출처: http://www.devpia.com/DevStudy/Lecture/OffLineDetail.aspx?nSemiID=1431&lectype=evt

데브피아에 DB 튜닝관련 컬럼 연재가 2회차가 올라왔습니다. ^^

 지난회에는 인덱스를 생성했으나 컬럼의 가공, 내부적 변형, null과의 비교, 부정형 조건등으로 인하여 인덱스를 사용하지 못하는 경우를 보았다.
그럼 과연 인덱스를 타기만 하면 무조건 빠를까?
불행하게도 그렇지 않다. 대부분의 경우는 빠르겠지만 경우에 따라서는 인덱스를 타기 때문에 느려지는 경우가 많이 발생한다.

EMPLOYEE에 성별 컬럼을 추가하고 절반정도 되게 남성과 여성을아래와 같은 분포도로 넣었다.

SELECT GENDER , COUNT(*) CNT, ROUND(COUNT(*) / 15132,3)*100 RATIO FROM EMPLOYEES
GROUP BY GENDER;

G
----
F
M
CNT
--------
7590
7542
RATIO
---------
50.2
49.8
 
그리고 아래와 같은 INDEX를 생성하였다.
CREATE INDEX IDX_GENDER ON EMPLOYEES(GENDER);
그러면 이제 2개의 SQL의 수행 결과를 보자.
첫번째 경우는 INDEX를 탄경우다.
아래와 같이 HINT를 주어서 OPTIMIZER의 PLAN을 고정하였다.
/*+ INDEX(E IDX_GENDER) */ 는 E라는 별명의 테이블에 IDX_GENDER이라는 INDEX를 이용하여 테이블에 데이터를 가져오라는 뜻이다.
SELECT /*+ INDEX( E IDX_GENDER) */ GENDER, COUNT(*), AVG(SALARY)
FROM EMPLOYEES E
WHERE GENDER = 'M'
GROUP BY GENDER

Call
----------
Parse
Execute
Fetch
----------
Total

Count
----------
1
1
2
----------
4
CPU Time
----------
0.000
0.000
0.030
----------
0.030
Elapsed Time
-------------
0.000
0.000
0.026
-------------
0.026
Disk
----------
0
0
0
----------
0
Query
----------
0
0
127
----------
127
Current
----------
0
0
0
----------
0
Rows
----------
0
0
1
----------
1
Misses in library cache during parse: 0
Optimizer goal: RULE
Parsing user: SCOTT (ID=54)

Rows
----------
0
1
7542
7542
Row Source Operation
---------------------------------------------------
STATEMENT
SORT GROUP BY NOSORT (cr=127 pr=0 pw=0 time=25567 us)
TABLE ACCESS BY INDEX ROWID EMPLOYEES (cr=127 pr=0 pw=0 time=15176 us)
INDEX RANGE SCAN IDX_GENDER (cr=16 pr=0 pw=0 time=61 us)OF IDX_GENDER (NONUNIQUE)
두번째 경우는 INDEX를 타지 않은 경우다.
아래와 같이 HINT를 주어서 OPTIMIZER의 PLAN을 고정하였다.
/*+ FULL(E) */ 는 E라는 별명의 테이블을 할 때 테이블 전체를 다 읽어서 처리(FULL TABLE SCAN)하라는 뜻이다.
SELECT /*+ FULL(E) */ GENDER, COUNT(*), AVG(SALARY)
FROM EMPLOYEES E
WHERE GENDER = 'M'
GROUP BY GENDER

Call
----------
Parse
Execute
Fetch
----------
Total

Count
----------
1
1
2
----------
4
CPU Time
----------
0.000
0.000
0.010
----------
0.010
Elapsed Time
-------------
0.000
0.000
0.014
-------------
0.015
Disk
----------
0
0
0
----------
0
Query
----------
0
0
115
----------
115
Current
----------
0
0
0
----------
0
Rows
----------
0
0
1
----------
1
Misses in library cache during parse: 0
Optimizer goal: RULE
Parsing user: SCOTT (ID=54)

Rows
----------
0
1
7542
Row Source Operation
---------------------------------------------------
STATEMENT
SORT GROUP BY NOSORT (cr=115 pr=0 pw=0 time=14410 us)
TABLE ACCESS FULL EMPLOYEES (cr=115 pr=0 pw=0 time=181 us)
인덱스를 탄 경우는 0.03초가 걸렸고 인덱스를 타지 않은경우는 0.01초가 걸렸다.
인덱스를 타서 3배나 더 느려졌다!. 이것이 가능한가? 그러면 왜 인덱스를 탔는데도 시간이 더 걸리는 것인가?
이유는 Disk io에 있다. 일반적으로 Full table scan을 할때는 한번에 1개의 block씩 i/o를 하지 않고 muti block를 한번에 요구한다. 그 이유는 읽을 양이 많다고 미리 가정하기 때문이다. 따라서 Oracle의 경우 db_file_multiblock_read_count라는 파라미터가 있고 일반적으로 8또는 16을 설정한다. 만약 16이라면 한번 I/O에 16개의 BLOCK을 읽어오게 되는것이다.
따라서 EMPLOYEE 115BLOCK을 한번에 16개씩 읽으면 약 8번의 IO 요청으로 완료가 된다.
그러나 Index를 사용할 경우 index를 사용하면 기본적으로 대량의 io가 발생할 것이라고 가정하지 않기 때문에 1개의 block씩 i/o를 하게 된다.
따라서 16개의 index block과 115개의 block의 물리적 i/o가 발생한다 16+115를 하면 총 131번의 물리적 io가 발생하게 되는것이다. 논리적으로는 인덱스 1개보고 테이블 1개 블락을 읽고를 7542번+1번을 하게되는 것이다. 마지막 1번은 다음에 더 이상 ‘M’이 없는지 확인하기위해서 1번 더 읽는다. 어째든 인덱스를 사용되는 것이 더욱 느리다는 것이다. 현지 EMPLOYEES 테이블은 15132건이다. 만약 이 데이터가 많아진다면 차이는 점점 더 많이 날것이다.

그러면 어느정도은 INDEX를 타고 어느 정도는 Full Table Scan이 오히려 더 좋은가?
시스템의 성능또는 데이터의 양에 따라 차이가 조금씩있으나 일반적인 기준은 있다.
아래 TYPE이라는 컬럼에 A-F까지 값을 가지고 있으며 가각 49.8%부터 0.9%까지의 분포를 가지는 값들을 가지고 있다.
SELECT TYPE , COUNT(*) CNT, ROUND(COUNT(*) / 15132,3)*100 RATIO FROM EMPLOYEES
GROUP BY TYPE;

T
--------
A
B
C
D
E
F
CNT
--------
7542
4533
1515
799
603
140
RATIO
---------
49.8
30
10
5.3
4
0.9
아래는 예제로 사용되었던 SQL과 그에 따른 응답시간을 비교한 표이다.

FTS(Full Table Scan) SQL
SELECT /*+ FULL(E) */ GENDER, COUNT(*), AVG(SALARY)
FROM EMPLOYEES E
WHERE TYPE = 'F'
GROUP BY GENDER;

Rows
--------
0
1
140
Row Source Operation
---------------------------------------------------
STATEMENT
1 HASH GROUP BY (cr=115 pr=0 pw=0 time=6925 us)
140 TABLE ACCESS FULL EMPLOYEES (cr=115 pr=0 pw=0 time=10323 us)
INDEX(Index Scan) SQL
SELECT /*+ INDEX(E IDX_TYPE) */ GENDER, COUNT(*), AVG(SALARY)
FROM EMPLOYEES E
WHERE TYPE = 'F'
GROUP BY GENDER;

Rows
--------
0
1
140
140
Row Source Operation
---------------------------------------------------
STATEMENT
HASH GROUP BY (cr=87 pr=0 pw=0 time=3227 us) 140
TABLE ACCESS BY INDEX ROWID EMPLOYEES (cr=87 pr=0 pw=0 time=2956 us)
INDEX RANGE SCAN IDX_TYPE (cr=2 pr=0 pw=0 time=539 us)OF IDX_TYPE (NONUNIQUE)
 
결과를 보자 약 15132건의 테이블을 ACCESS하는데 10%이상이 되는 경우는 FTS이 더빠르고 10%이하인 경우는 INDEX를 타는 경우가 더 빠르다.
10% 미만일때는 INDEX를 타고 10%가 넘으면 인덱스를 안타게 할수 있는가?
결론적으로 가능하다.
아래 SQL을 보자 2개의 SQL을 UNION ALL로 결합하고 비교조건을(굵은색)을 줌으로서 논리적 비교를 통해서 실제로 FTS의 조건은 타지 않고 INDEX쪽만 수행하도록 하였다.
아래 수행결과를 보면 INDEX를 타는 곳에서만 ROWS가 나온 것을 알수있다.
SELECT /*+ FULL(E) */ GENDER, COUNT(*), AVG(SALARY)
FROM EMPLOYEES E
WHERE TYPE = 'F'
   AND TYPE IN ( 'A','B','C')
GROUP BY GENDER
UNION ALL
SELECT /*+ INDEX(E IDX_TYPE) */ GENDER, COUNT(*), AVG(SALARY)
FROM EMPLOYEES E
WHERE TYPE = 'F'
   AND TYPE IN ( 'D','E','F')
GROUP BY GENDER;

Rows
--------
0
1
0
0
0
1
140
140
Row Source Operation
---------------------------------------------------
STATEMENT
UNION-ALL (cr=87 pr=0 pw=0 time=2743 us)
HASH GROUP BY (cr=0 pr=0 pw=0 time=235 us)
FILTER (cr=0 pr=0 pw=0 time=8 us)
TABLE ACCESS FULL EMPLOYEES (cr=0 pr=0 pw=0 time=0 us)
HASH GROUP BY (cr=87 pr=0 pw=0 time=2477 us)
TABLE ACCESS BY INDEX ROWID EMPLOYEES (cr=87 pr=0 pw=0 time=2328 us)
INDEX RANGE SCAN IDX_TYPE (cr=2 pr=0 pw=0 time=205 us)OF IDX_TYPE (NONUNIQUE)
그렇나 이렇게 프로그램을 한다면 프로그램이 힘들어 질것이다. 따라서 현재 Optimizer들은 실제 값에 따라서 FTS이 유리한지 아니면 INDEX SCAN이 유지한지 값을 보고 PLAN이 바뀌도록 되어있다. 물론 이를 위해서는 컬럼에 대한 분포도 정보를 DB가 가지고 있어야 한다. 이는 ANALYZER를 통해서 DB가 취득하게 된다.

그럼 이제 간단하다 10%이상에 데이터를 INDEX를 타면 속도가 오히려 느려지므로 10%이하의 데이터를 찾고자 할 때만 INDEX를 생성하면 간단하게 해결될것이다!
그러나 과연 그럴까?
INDEX를 생성하면 일반적으로 SELECT의 속도는 향상을 보지만 반대로 INSERT,UPDATE,DELETE는 저하되게 된다.
위에 도표를 보면 INDEX의 숫자가 증가함에 따라서 속도가 느려지는 것을 알수 있다. 즉, 인덱스의 생성으로 SELECT는 빨라질수도 있고 느려질수도 있다. 그러나 DML(INSERT,UPDATE,DELETE)는 항상 느려진다. 따라서 INDEX를 무작정 다는 것은 DML 성능을 느리게 한다.
그럼 어떤 기준으로 인덱스를 생성할지 말지를 결정할 것인가?
아래 2가지 시간을 고령하자.
이익시간 = INDEX생성으로 빨라진시간 * 수행 QUERY수
비용시간 = INDEX생성으로 느려진 INSERT시간 * INSERT수행횟수
                + INDEX생성으로 느려진 UPDATE시간 * UPDATE수행횟수
                + INDEX생성으로 느려진 DELETE시간 * DELETE수행횟수

이익시간이 비용시간 보다 크다면 인덱스를 생성하는 것이 좋을 것이다. 반대로 이익시간 < 비용시간 보다 작다면 인덱스를 만드는 것이 손해보는 경우다.
이런 경우라면 인덱스를 만들면 안되는 것이 유리하다 할수 있다. 그러나 반드시 그런 것은 아니다. 그것은 수행 시간을 고려해야한다. 낮에일반적으로 QUERY가 빠르게 수행되고 주로 밤에 BATCH에서 DML이 수행되고 있다고 가정할 때 DML이 더 느려지는 것이 그렇게 문제가 되지 않는다면 INDEX를 생성할 수도 있는것이다. 어디까지나 Application 사용의 관점에서 효율적인 것을 찾는 것이 중요하다.
인덱스를 사용하여 손해보는 경우는 아래와 같다.

  • 같은 값이 많은 컬럼
    • INDEX를 타면 10%이상 선택하는 경우
    • 예) 남녀성별등..
  • 조회보다 DML의 부담이 큰 경우
    • 이익시간 < 비용시간 경우
    • 그러나 이때도 사용환경을 고려하여 인덱스를 생성할 수 있다.
  • 데이터가 적은 테이블
    • 일반적으로 db_file_multiblock_read_count보다 적은 수의 BLOCK을 가진테이블은 INDEX를 타지 않는 것이 빠르다.
    • 그러나 integrity를 위해서 PK와 FK는 달아야 한다.

이번 회에는 INDEX를 타서 오히려 손해를 보는 경우와 그를 방지하는 방법을 보았다.
인덱스를 생성한다고 인덱스를 반드시 타는 것도 아니며 또한 인덱스를 탄다고 반드시 빠른 것도 아니다. 따라서 INDEX의 생성과사용 전략은 그렇게 쉬운 문제가 아니다. 빠른 시스템을 위해서는 고려할 점이 많다는 것이다. 물론 필자가 다룬 것은 테이블중에 일반테이블과 일반 INDEX에 대해서만 다루었기때문에 PARTITION이나 BITMAP같은 다른 구조의 인덱스에서는 다른 특성을 가진다. 그러나 이러한 것은 대용량이나 DW의 특수한 용도에 사용되므로 대부분의 경우에는 고려하지 않아도 크게 문제되지 않을 것이다.

못조록 필자의 글이 독자들에게 도움이되는 길이기를 바라면서 이글을 마무리하고자 한다.
마지막으로 당부 드리고 싶은 말은 SQL을 작성하시고 항상 PLAN을 확인하시기 바랍니다.
PLAN에 익숙해지고 OPTIMIZER를 이해할 때 비로소 OPTIMIZER가 여러분의 심부름꾼이 될수 있기때문이다.



반응형
Jar 파일로 응용프로그램을 배포하다 보면 이미지 화일이나 프로퍼티 화일, 자료화일등을

함께 묶어서 배포할 경우가 있다. 해당 자원에 접근하기 위해서는 이전에도 포스팅한바가 있는

java.lang.ClassLoader을 이용해 해당 자원에 접근 할수 있다.

간단한 예를 보자.
ClassLoader loader = this.getClass().getClassLoader();
Icon tIcon = new ImageIcon(loader.getResource("res/tImag.git"));

그 외에도 ClassLoader.getResourceAsStream(String name) 메소드를 이용하여
InputStream을 통한 방법도 있다.

자바웹스타트 환경에서는 Java 2 SE API에서 제공하지 않는 추가적인 기능을 하는 API를
제공한다. 이것은 JNLP API라고 한다. JNLP API를 이용하여 개발할 경우는 jnlp.jar가
필요한데 이러한 파일은 JNLP Developer's Pack에 포함 되어 있다. 다음은 Developer's Pack을
다운로드 할 수 있는 URL이다.

http://java.sun.com/products/javawebstart/download-jnlp.html

  JNLP API가 추가적으로 제공하는 클레스는 javax.jnlp package로 묶여 있으며
BasicService, ClipboardService, DownloadService, FileOpenService, FileSaveService, 
PrintService, PersistenceService 등이 있는데 이들은 ServiceManager 클레스를 통하여
사용할 수 있다. 각각의 기능은 다음과 같다.

- javax.jnlp.BasicService

BasicService는 웹스타트의 환경적인 면이나 브라우져를 통제하기 위한 API를 제공하는데
자바 애플릿의 경우 AppletContext와 비슷한 역할을 한다. 다음 예제는 웹스타트 환경에서
웹브라우져로하여금 특정 URL로 가도록 하는 것이다.

import javax.jnlp.*;
.....

BasicService bs = (BasicService)ServiceManager.lookup("javax.jnlp.BasicService");
bs.showDocument(new URL("http://www.javanuri.com"));



- javax.jnlp.ClipboardService

ClipboardService는 시스템에서 사용하는 클립보드에서 복사 객체를 가져오거나 클립보드로
복사하는 서비스를 제공한다. 자바웹스타트는 이 기능을 사용할 때 보안을 위하여 경고창을
보여준다. 다음은 간단한 스트링을 클립보드에 복사하는 예제이다.

import javax.jnlp.*;
.............

ClipboardService cs = (ClipboardService)ServiceManager.lookup("javax.jnlp.ClipboardService");
StringSelection ss = new StringSelection("Hello Web Start");
cs.setContents(ss);


- javax.jnlp.DownloadService

DownloadService는 자신의 자원을 Cache에 저장, 삭제등 Cache를 통제할 수 있는 서비스 API를
제공하는 클레스이다. 다음은 myapp.jar를 Cache에서 확인하고 있으면 삭제한후 다시 Cache에
저장하는 예제이다.

import javax.jnlp.*;
...........

DownloadServicd ds = (DownloadService)ServiceManager.lookup("javax.jnlp.DownloadService");
URL url = new URL("http://www.javanuri.com/jws/myapp.jar");
boolean isCached = ds.isResourceCached(url, "1.0");
if(isCached) {
  ds.removeResource(url, "1.0");
}

DownloadServiceListener dsl = ds.getDefaultProgressWindow();
ds.loadResource(url, "1.0", dsl);


- javax.jnlp.FileOpenService

FileOpenService는 권한이 제약된 환경에서도 이를 사용자에게 알리고 화일을 열 수 있는
다이얼로그 윈도우를 열어주는 서비스이다.  다음 예제는 FileOpenService를 이용하여 화일을
여는 예제이다.

import javax.jnlp.*;
..............

FileOpenService fo = (FileOpenService)ServiceManager.lookup("javax.jnlp.FileOpenService");
FileContents fc = fo.openFileDialog(null, null);

- javax.jnlp.FileSaveService


FileSaveService는 권한이 제약된 환경에서도 local disk에 화일을 저장할 수 있는
기능을 제공하는 서비스 클레스이다. 이는 FileOpenService의 경우와 반대인 기능을 제공하는
클레스이다.  다음은 FileOpenService를 이용하여 화일을 연 후에 FileSaveService를
이용하여 화일을 저장하는 예제이다.

import javax.jnlp.*;
.....................

FileOpenService fo = (FileOpenService)ServiceManager.lookup("javax.jnlp.FileOpenService");
FileContents fc = fo.openFileDialog(null, null);
FileContents newfc = fss.saveFileDialog(null, null, fc.getInputStream(), "newfile.txt");

- javax.jnlp.PrintService

PrintService는 권한이 제약된 웹스타트 환경에서도 프린트를 가능하게 해주는 API 를 갖고 있는
서비스 클레스이다.  이 API를 이용하여 프린트를 요청하면 사용자에게 허가할 것인가를 묻는
다이얼로그가 나타난다. 다음은 PrintService를 이용한 프린트 요청 예제이다.

import javax.jnlp.*;
.....................

PrintService ps = (PrintService)ServiceManager.lookup("javax.jnlp.PrintService");

// default page format
PageFormat pf = ps.getDefaultPage();

// customizing page format
PageFormat npf = ps.showPageFormatDialog(pf);

// print
ps.print(new Doc());


// printable class
class Doc implements Printable {

 ....
 public int print(Graphics g, PageFormat fm, int idx) {
  ....
 }

}

}


- javax.jnlp.PersistenceService

PersistenceService는 브라우져의 쿠키와 마찬가지고 사용자의 클라이언트에 간단한 자료를 
저장할 때 사용된다. 저장되는 형태는 url형태로 자장된다.
다음은 간단한 url을 저장하고 내용을 읽어들이는 예제이다.


import javax.jnlp.*;
.....................

PersistenceService ps = (PersistenceService)ServiceManager.lookup("javax.jnlp.PersistenceService");

String addr = "www.javanuri.com/some.txt";
java.net.URL = new URL(addr);

// create
ps.create(url, 1024);
FileContents fc = ps.get(url);
OutputStream os = fc.getOutputStream(false);
os.write(...);

// read
fc = ps.get(url);
InputStream in = fc.getInputStream();

in.read(...);

.......


- javax.jnlp.FileContents

FileContents 는 FileOpenService, FileSaveService, PersistenceService와 같은 서비스에서 
input과 output을 처리할 수 있도록 만들어진 클레스이다. 일반적인 File 클레스와 비슷하게
생각하면 된다.  보안과 자료 저장 형태 등이 일반 File 클레스와는 다르다. 
반응형

악의적인 의도로 리버싱을 하지 않습니다.

리버스 엔지니어링에 대한 순수한 학구열과 도전정신의 산물입니다.

또한 관련된 패치 프로그램과 패치 방법등에 대해서 알려주거나 배포하지 않습니다.

참고로 프로그레스바에 대한 패치는 아직 못하였습니다.
윈도우프로그래밍에대한 지식이 부족하기 때문에 좀더 공부의 필요성을 절실히 느끼네요.
윈도우API 책을 사놓고 펴보지도 못하고 있는데 이번 기회에 좀 봐야겠네요.


반응형
출처: http://www.idg.co.kr/newscenter/common/newCommonView.do?newsId=52482

임철우님의 컬럼입니다. 전에도 스크랩해서 다른 글을 포스팅한적이 있습니다.

시간을 내서 다시 찾아서 못읽었던 다른 컬럼을 읽고 또 포스팅 합니다.

요즘은 거의다 스크랩해서 올리게 되는거 같군요. 임철우님의 컬럼 시간내서 읽어보시길..

정말 좋은 글들이 많이 있습니다.  가슴에 와닿는 글들도 많고..

 

AP76F8.JPG해마다 이맘때면 시내 한복판에서 쉽게 구세군들을 만날 수가 있다. 그들이 왜 추운 거리에서 자그마한 정성을 모아 불우한 이웃을 돕자고 열심히 종을 치며 사랑의 모금을 하는지 생각해 볼 필요가 있다. 무엇인가 나눌 것이 있다는 것은 참 행복한 것이다. 어쩌면 손해를 본다는 생각이 들겠지만 조금만 다른 시각에서 바라보면 전혀 다른 행복이 보이기 시작할 것이다.

  

개발자라면 꾸준히 새로운 지식을 익힐 필요성을 느끼게 될 것이다. 필자가 처음 개발자로 입문을 했을 당시에는 지금처럼 인터넷이 활성화가 안 되어 있던 시절이었고 개발을 하다 막히는 부분이 있으면 하루고 이틀이고 밤을 새워가며 해결하기 위해 끊임없이 원인을 찾기 위해 노력을 해야만 했다.

 

한번은 문제가 해결될 기미도 안보이고 거의 포기 상태까지 이르렀을 때 같이 일하던 A선배가 비슷한 경험이 있다며 힌트를 주었고, 그로 말미암아 다른 관점에서 접근을 하게 되어 일을 기한에 맞추어 끝냈던 기억이 난다.

 

반면, 당시 실력은 월등히 좋았지만 옆에서 힘들어 하는 걸 뻔히 보면서도 도움을 주지 않았던 B라는 선배도 있었다. 그 이후에도 A선배는 뛰어난 실력은 아니어도 자신이 알고 있는 것을 정리해서 가끔 필자에게 알려 주었고, 덕분에 다양한 개발 팁을 배우게 되는 등 회사 생활을 하는데 많은 도움을 받았다. B선배의 경우는 어려운 일을 혼자서 다 처리했기에 역시 회사 생활을 하는데 도움을 받은 것은 사실이다.

 

하지만 A, B선배와는 서로 다른 회사로 옮기면서 확실하게 차이가 벌어지게 되었다. A선배와는 계속 연락하며 지내지만, B선배와는 연락을 하는 일이 전혀 없어진 것이다. A선배와는 왠지 모르는 인간적인 유대가 생겼고 B선배와는 그저 일 때문에 만난 사람이기에 더 이상 관계가 발전되기 힘들기 때문이다. 직장에서 만난 사람들과 오랫동안 서로 알고 지내는 일은 솔직히 좀처럼 쉽지 않다.

  

실력이 우선시 되는 사회인 것만은 사실이다. 하지만 독불장군처럼 알고 있고 기술을 나눌 줄 모르는 사람이라면 아마도 개발자로서 오랫동안 생활하기에는 어려움이 있을 것이다. 모든 지식을 혼자서 다 익힐 수는 없기 때문이다. 그리고 자기만 알고 있다고 생각하는 신기술 또한 알고 있는 사람이 있기에 자신도 알고 있는 것이고 그렇다면 언젠가는 다른 사람들 또한 알게 될 것이다. 어떤 사람이 그 기술을 공유하려고 할 때 "나도 알고 있는데…" 이런 말을 하게 된다면 한다면 오히려 욕을 먹을지도 모른다.

  

현재 거의 모든 프로젝트는 여러 사람이 톱니바퀴처럼 딱딱 맞아야 비로소 성공적인 프로젝트로 갈 수 있다. 내가 알고 상대가 모른다면 지식을 공유해야 하는 것이 개발자의 예의라고 생각한다. 기술의 공유에 있어서 지위가 높고 낮음은 없으며, 새로운 지식을 습득하게 되면 다른 사람들과의 공유는 필수이며, 알려주려고 하는 사람을 오히려 잘난 척 한다고 생각하는 사람이 있다면 그 사람은 남보다 발전이 늦을 것이며 그 사람은 왜 쉽게 갈 수 있는 길을 어렵게 돌아가려 하는지 생각해봐야 한다. 사전 정보를 가지고 시작하는 것과 모르고 시작하는 것은 천지차이다.

  

신기술이나 팁을 공유함으로써 자신에 돌아오는 것이 무엇인가? 그것은 사람이다. 바로 이것이 나누면 행복해지는 이유이다. 나를 인정해주고 어려움이 닥쳐도 함께 해줄 동료가 한 명이라도 있다면 개발자로서 성공한 거라고 생각한다. 이 글을 통해 내가 지금 힘들 때 정말 나를 도와줄 개발자가 몇이나 되고 연락 가능한 사람이 몇이나 되는지 돌아보는 계기가 되었으면 좋겠다.



반응형
출처: http://www.idg.co.kr/newscenter/common/newCommonView.do?newsId=51142

CPU 오버클러킹

 

난이도: 보통

소요시간: 오전 중 10분

 

 

약간의 수고만으로도 시스템의 속도를 10% 이상 증가시킬 수 있다. 대다수의 CPU는 최대 한도보다 낮게 설정된 채로 출고된다. 일부 제품은 종종 속도를 향상시킬 수 있는 방법이 함께 제공되기도 있다.

 

많은 사람들의 우려와 달리 오버클러킹은 PC에 크게 위험하지도 않고 조작하기 어렵지도 않다. 물론 오버클러킹 시 제품 보증서의 효력은 공식적으로 사라지지만 말이다.

 

반면 오버클러킹이 가능한 기성 PC제품들은 흔치 않다. 일단 자신의 PC가 오버클러킹을 지원하는지 확인해 보자. 만약, 여러분의 PC가 오버클러킹을 지원한다면, 수 분 내에 PC의 속도를 개선시킬 수 있다. 참고로 높은 성능 및 안정성을 얻고 싶다면, 오후 시간대는 피하여 테스트해 보는 것이 좋다.

 

오버클러킹을 하기 위해서는 우선 정보를 모아야 한다. 마더보드의 모델을 확인하고, 해당 모델의 매뉴얼을 다운로드 받은 다음 BIOS를 최신 버전으로 업데이트시킨다. 마더보드 제조사가 윈도우용 오버클러킹 유틸리티들을 제공하는 경우도 있지만 가급적 BIOS 내에서 직접 설정내역을 변경하는 것을 권장한다. 이 경우 설정을 재변경하기 전까지 설정내역이 유지된다.

 

다음으로는 BIOS에 액세스 하는 방법 및 업그레이드가 불안정할 경우(애플리케이션이 충돌하거나 시스템이 다운되는 현상 등)를 대비해 이를 디폴트 구성으로 재설정할 수 있는 방법을 파악해야 한다. PC가 부팅되지 않은 경우 재설정을 하기 위해서는 물리적으로 점퍼 스위치를 변경시키거나 마더보드의 버튼을 눌러야만 하는 경우가 있는데, 이를 알아두어야 한다는 이야기다. 그렇지 않으면, 문제 발생시 BIOS 화면으로 돌아가는 길을 찾지 못해 컴퓨터가 잠겨 버리게 된다.

 

아울러, 온라인으로 CPU의 모델을 파악하고 (BIOS에서 이와 관련된 일부 정보들을 찾을 수 있다) 해당 모델이 지원하는 온도를 확인하도록 한다. 오버클러킹이 성공적으로 이루어지기 위해서는 성능과 열을 절충하여 선택해야만 한다. CPU가 너무 뜨거워지면 PC가 충돌을 일으키게 된다. 오버클러킹을 진행하면서 BIOS에서 온도를 체크하도록 한다.

 

때때로 BIOS는 ‘Al’ 모드, 자동 모드를 통해 CPU를 성공적으로 오버클러킹시킬 수도 있다. ‘Al’ 모드를 선택할 수 있다면, 오버클러킹은 한마디로 식은죽 먹기다. 그러나, 대부분의 경우는 버스(FSB) 스피드의 설정을 변경하여 CPU의 속도를 향상시키게 된다. BIOS 내에서 FSB 스피드를 5-MHz나 10-MHz정도 올리고, 변화를 저장한 뒤, 재부팅하는 방식이다.

 

만약 PC가 성공적으로 부팅되지 않는다면, 즉, 윈도우 화면이 나타나지 않는다면, BIOS 화면으로 돌아가 FSB 스피드를 기존의 설정대로 복귀시켜야 한다. 복귀 후 부팅이 성공적으로 이루어진다면, 다시 한 번 FSB 스피드를 조금씩 증가시킨 다음 약 30분간의 Prime95 테스트를 통해 CPU가 제대로 작동하는 지를 확인하도록 한다.

 

Prime95는 오버클럭된 CPU에 부하를 주어 안정적으로 작동하는 지를 확인하는 테스트다. Prime95 테스트에서 시스템이 안정적으로 작동한다면, FSB 스피드를 천천히 조금씩 증가시키는 것을 계속하도록 한다.

 

이 과정 중 성능상의 문제나 충돌이 발견된다면, 혹은 CPU가 너무 뜨거워 진다면, FSB 스피드를 줄여 안정적인 수준을 찾아야 한다. 온도를 낮게 유지하기 위해 CPU의 히트 싱크를 업그레이드하는 것도 좋다. ; 더욱 튼튼한 히트 싱크는 FSB 스피드를 조금 더 올려줄 수 있다.

 

그래픽카드 오버클러킹

 

난이도: 쉬움

소요시간: 60분

 

 

ATI와 엔비디아는 모두 일부 고성능 비디오 카드에 한해 무료 오버클러킹 툴을 제공하고 있다. 이 방법은 BIOS의 설정을 변경하지 않고도 시스템의 그래픽 성능을 향상시켜 준다. 속도가 빨라짐에 따라 게이머들은 더욱 부드러운 비디오 영상을 즐길 수 있을 것이다. 시작하기에 앞서 그래픽 보드의 드라이버를 업그레이드 정도는 해두자.

 

엔비디아의 컨트롤 패널(Control Panel)에서 퍼포먼스(Performance)로 들어가 디바이스(Device) 설정을 클릭한다. GPU를 클릭하고, 커스텀(Custom)을 선택한 뒤, 안정성을 확인해 가면서 슬라이더를 이동시켜 클럭 스피드를 증가시키도록 한다.

 

ATI 카드를 사용하고 있다면, 카탈스트 컨트롤 패널(Catalyst Control Panet)을 열고 오버드라이드(Overdrive)로 들어가 자동조정(Auto-Tune)을 클릭한다. 이 방법은 점진적으로 클럭 스피드를 증가시키면서 연달아서 각 스피드를 테스트한다. 불안정성이 발견되면, 클럭 스피드를 감소시켜 기존 수준으로 복귀시킨다.

 

에너지 절감을 위한 PC 다운클러킹

 

난이도: 쉬움

소요시간: 20분

 

많은 사람들이 무료로 시스템의 속도를 향상시키기를 원하지만, 에너지 절감과 열 차단을 중시하는 사용자라면 하드웨어를 다운클러킹 시키는 것이 더 나은 선택일 수도 있다. 물론, 다운클러킹에 따른 에너지 절감폭은 그리 기대할 만한 수준이 아니지만 말이다.

 

조용한 시스템이 요구되는 홈시어터PC에서도 다운클러킹을 고려해 볼 수 있다. 온도를 낮춰주면서 쿨링팬이 돌아가는 소리가 조용해지기 때문이다.

 

시스템을 다운클러킹시키기 위해서는, 이전 페이지에 위에서 언급한 오버클러킹 조언들을 따르되 CPU의 속도를 증가시키는 것이 아니라 감소시키면 된다. 또 윈도우의 전원 옵션(Power Options) 컨트롤 패널에 들어가 상세 설정을 변경하도록 한다.

 

프로세서 전원관리(Processor power management)를 클릭하고 최저 속도와 최고 속도를 변경해라. 필요시 CPU의 속도를 증가시킬 수 있도록 최저 속도를 5%, 최고 속도를 100%로 설정한다. 만약 이메일 등 기본적인 업무를 위해서만 PC를 사용한다면 최고 속도를 좀 더 낮게 설정하면 된다.

 

안테나 추가로 무선랜 범위 확대

 

난이도: 쉬움

소요시간: 45분

 

 

간단하고 수동적인 파라볼라 반사기(Parabolic Reflector)를 무선 안테나 주변에 설치함으로써 신호를 정확히 원하는 지점에 집중시킬 수 있다. 파라볼릭 반사기는 네트워크의 범위를 넓혀줄 뿐만 아니라 네트워크의 보안까지도 개선시켜줄 수 있다.

 

적합한 안테나 모양을 찾으려면 파라볼라 계산기를 다운로드하는 것이 좋다. 라우터의 안테나가 물리적으로 수용할 수 있는 최대 규모의 반사기의 직경 및 깊이를 입력해라. 파라볼라 계산기는 모눈 종이에 설계도를 그릴 수 있도록 수치표를 산출해 줄 것이다. 두 장의 마분지에서 파라볼라 모양을 잘라낸 다음, 부드러운 금속 조각을 잘라 반사기로 사용하도록 한다. 금속조각을 U자형으로 구부려 유도장치를 둘러싸도록 한 다음 본드로 붙여 고정시킨다. 마지막으로 유도장치의 초점 부분에 작은 구멍을 내고 반사기를 설치한다.

 

무선 라우터에 고급 기능 추가

 

난이도: 보통

소요시간: 45분

 

 

사용하다 보면 무선 네트워크를 확장해야 할 필요성을 느낄 수도 있다. 그러나, 그렇다고 해서 반드시 새로운 네트워킹 하드웨어를 구입할 필요는 없다. 써드파티의 펌웨어를 사용해 기존의 무선 라우터에 새로운 기능을 더함으로써 네트워크의 확장이 가능하다.

 

이 경우, 라우터의 성능을 새 장비를 구입하는 것과 대등하게, 혹은 (많은 경우) 그 이상으로 개선시킬 수 있다. 이 해킹 방법을 통해 사용자들은 안테나의 파워를 증가시키고, 리피터가 더욱 넓은 Wi-Fi 범위를 지원할 수 있다. 또 무선 네트워크의 보안을 개선시키며, Wi-Fi 트래픽을 유선 네트워크에서 분리시키고, VPN을 설치하는 등 많은 긍정적 효과들을 기대할 수 있다.

 

X-Wrt 펌웨어는 아수스, 버팔로, 링크시스를 포함한 많은 라우터를 지원한다. 웹사이트를 방문해 X-Wrt 펌웨어가 각자의 라우터를 지원하는 지 확인하도록 한다. (만약, 라우터가 지원 가능한 라우터 목록에 포함되지 않는다면, 온라인에서 해당 라우터 모델에 대한 펌웨어를 검색해 보자. 여러분의 라우터를 지원하는 유사한 펌웨어가 있을지도 모르기 때문이다.)

 

이더넷 케이블을 사용하여 라우터를 PC에 직접 연결시킨 다음 라우터의 구성 페이지에서 로그인한다. 시스템 설정 메뉴를 열고 펌웨어 옵션을 살펴본다. 버튼을 클릭해 새로운 펌웨어 파일을 선택한 다음, 이를 라우터로 업로드시킨다. 업데이트가 종료되기 전까지는 라우터와 PC를 분리해서는 안 된다. 그렇지 않으면, 하드웨어가 영구적으로 손상될 위험이 있다. 이 과정에는 최대 15분의 시간이 소요된다.

 

업데이트가 종료되고 라우터가 재시작하면, 브라우저를 사용하여 무선 네트워크를 다시 연결한다. 곧 디폴트 화면 대신 X-Wrt 인터페이스가 나타나면서 사용자로 하여금 신규 패스워드를 설정하도록 한다. 이제 무선 인터넷을 재연결할 수 있다. 그러나, 이는 이더넷을 통한 대부분의 관리업무들을 수행하는 데 있어서는 최고의 방법이다.

 

펌웨어 업데이트 메뉴에서 네트워크(Network)로 들어가 무선 설정(Advanced Wireless Settings), 그리고 전력 송신(Transmit Power)을 클릭한 후 송신 전력을 변경해라. 무선 네트워크의 지원 범위를 확대해야 할 경우에는 수치를 높이고, 네트워크가 이웃집까지 흘러가는 것을 막고 싶다면 수치를 낮추면 된다.

 

네트워크 탭 내에 있는 QoS를 이용하여 특정 P2P 프로그램들의 우선 순위를 낮춰 긴급한 업무가 발생할 시 항상 가능한 모든 대역폭을 사용할 수 있도록 디폴트 서비스 품질을 설정하는 것도 가능하다.

 

그래프(Graph) 탭으로 들어가면 사용 대역폭 및 기타 정보들의 실시간 차트를 볼 수 있다. 각 페이지마다 오른쪽 하단에 있는 저장(Save Changes) 버튼을 눌러 변경 내역을 저장하고, 업데이트를 할 준비가 되었다면 적용(Apply Changes) 버튼을 누르는 것을 잊지 마라. 만약, 기본 펌웨어로 복귀하고 싶다면, 라우터 제조사의 웹사이트에서 이를 다운로드한 뒤 시스템에 업로드시키고 페이지를 업그레이드(Upgrade) 하면 된다.

반응형
출처: http://www.hauri.co.kr/customer/security/colum_view.html?intSeq=89&page=1&keyfield=&key=

악성코드 짜잉나는 놈 내 손으로 제거해 주마!!! ㅎㅎ

악성코드 관련 컬럼이 있어 퍼왔습니다. 눈에 익은 툴들이 몇개 보이네요....ㅎ

 

1. 악성코드의 형태


악성코드는 대부분 스스로 실행 가능한 .exe 형태이거나, 다른 프로세스에 인젝션 되어 실행되는 .dll형태로 존재한다. 이번 칼럼에서는 간단하게 .exe형태의 악성코드를 제거해보도록 하겠다. 왜냐하면 .exe형태의 프로세스가 .dll형태의 악성코드보다 인지하는게 수월하기 때문이다.


2. 유용한 확인/제거 툴


ㄱ. Process Explorer 작업관리자로도 .exe형태의 파일을 볼 수는 있지만, 프로세스명만 나오기 때문에 많이 부족하다.이를 보완해줄수 있는 툴이 Process Explorer이다. 이 툴은 간단하게는 이미지(파일) 경로와 프로세스명, User Name등을 알 수 있으며, 프로세스의 실행, 일시정지, 재실행, 종료등 여러가지 기능을 가지고 있다.


ㄴ. Autoruns 레지스트리를 확인할 수 있는 툴로 부팅시 자동실행되는 파일이나 서비스를 보여준다. 이것을 이용해서 재부팅시 실행되는 악성코드도 확인 할 수 있다.


ㄷ. IceSword / Gmer 루트킷 탐지와 숨겨진 프로세스, 파일 등을 종료시키거나 제거할 때 사용한다.


ㄹ. File Monitor / Registry Monitor 파일이나 레지스트리의 IO를 사람의 눈으로 확인하기가 힘들기 때문에, IO에 대한 로그를 보고IO를 확인하는데 사용한다.


ㅁ. taskkill 하나 이상의 프로세스를 종료하는데 사용하며 여러가지 조건을 줄 수 있다.


3. 악성코드에 감염된 PC를 찾아라


악성코드를 제거하기 위해서는 감염된 PC가 필요한데 실PC가 감염되면 좋을게 하나도 없다. 이럴때 필요한 것이 가상머신인데 VmWare, VirtualPC, VirtualBox등 여러가지가 있다. 자신에게 맞는 가상머신을 설치하고 OS도 설치하여 필요한 툴도 넣고, 마지막으로 스냅샷 등의 복원지점도 설정해놓아야 편안하게 감염 테스트를 할 수 있다.


ㄱ. 필자는 VirtualBox를 이용해 보았으며 툴도 넣어두었고, 복원지점을 위해 스냅샷도 찍어 두었다. 숨길건 없지만, 안개효과를 내주는 Blur 필터를 추가하니 이미지가 멋있어졌다.



 

ㄴ. 가상머신에 공유폴더를 이용하여 악성코드와 툴을 넣고 File Monitor를 실행해두고, 악성코드인 TEST_MAL.vir.exe를 실행시켰다. 악성코드가 C:\lsass.exe를 생성시키는 것을 알수 있었다.


(설정변경 : 메뉴의 Help밑에 보이는 깔때기 아이콘 실행 -> Highlite에 Write;Delete 추가)



ㄷ. 이제 악성코드는 TEST_MAL.vir.exe와 C:\lsass.exe 두 마리다.


실행중인 악성코드를 보기위해 Process Explorer을 실행시켜 악성코드를 지켜보니 처음에 실행한 악성코드 TEST_MAL.vir.exe와 계속해서 실행/종료를 반복하고 있는 C:\lsass.exe를 확인할 수 있다.


(빨간색 줄은 종료되는 프로세스를, 녹색줄은 이제 막 실행되고 있는 프로세스를, 보라색은 압축되어 있는 프로세스를 나타낸다.)



 

4. 악성코드 제거하기


이제 감염된 PC가 생겼으니 제거해보자. 원래 쉬운것부터 해나가야 실력이 늘것이고, 주유소 습격사건의 유오성처럼 한 놈만 잡으면 다른것도 응용해서 할 수 있을꺼라 생각한다. 대부분의 악성코드를 직접 감염시켜보는게 아니기 때문에 어떤 프로세스를 종료시켜야 할 지 난감할 것이다. 이 많은 프로세스중에 어떤게 악성코드일까?


ㄱ. 악성코드 의심 대상을 좁혀라.


(Services로 실행되는 악성코드는 예외) Process Explorer가 트리구조로 보여주는 것을 감안하여 Shell로 동작하는 explorer.exe의 자식노드(우측으로 치우친)로 보여지거나, (모니터를 기준으로) explorer.exe의 아래쪽에 존재하는 프로세스들을 자세히 들여다 보자. 이는 우리가 PC에 로그인하여 실행하는 프로그램들은 쉘에서 실행되기 때문이며, 예외적으로 쉘에서 실행된 것중 자식프로세스를 생성하고 죽을경우 Process Explorer는 해당 자식 프로세스를 쉘과 동등한 레벨로 보여주기 때문이다.


(이것은 마치 SI로 추정되는 사람을 특정국가에서 귀국한 사람들로 범위를 좁혀가는 것과 같은 것이다. 하지만 사람은 악성코드가 아니다.)


ㄴ. 하나씩 제외시키면 악성코드가 보인다. 평소에 자신이 많이 보았거나 확실하게 아는 프로세스를 제외해보면 몇 개 안남을 것이다. 지금 같은 경우는 TEST_MAL.vir.exe와 실행/종료를 반복하는 lsass.exe만 눈에 띄게 이상하다. ㄷ. 의심되는 프로세스를 찾았다. 정말 악성코드일까?


- 백신업체에 해당 파일을 압축암호와 함께 압축하여 신고


=> 악성코드의 신고접수는 자신뿐 아니라 많은 백신 이용자들이 PC를 쾌적하고 안전하게 사용할 수 있게 해준다. 많은분들이 계속해서 신고해준다면 더 좋아지지 않을까?


- 각 백신업체의 홈페이지에서 무료로 검사해 볼 수 있다.


- 여러 백신업체의 스캐너로 악성코드를 무료로 검사해준다.


=> http://www.virustotal.com/ko


=> http://virscan.org


ㄹ. 확신이 섰다면 악성코드를 종료하자. 실행중인 악성코드를 종료하기 위해 Process Explorer에서 해당 악성코드를 선택하여 마우스 우측버튼을 누르면 나오는 메뉴중 [Kill Process] 를 선택하면 해당 프로세스가 종료되고, [Kill Process Tree]를 선택하면 해당 프로세스 및 해당 프로세스의 자식 프로세스까지 같이 종료된다. - TEST_MAL.vir.exe, lsass.exe -> 마우스 우측버튼 -> Kill Process/Kill Process Tree



 

ㅁ. 어라.. 아직 남았네.


Process Explorer로 TEST_MAL.vir.exe는 종료되었지만, 실행/종료를 반복중인 lsass.exe는 끄떡도 안한다. 일반적인 바이러스의 경우 Process Explorer, IceSword, Gmer, 추가적으로 Autoruns면 끝을 보는데 실행/종료를 반복하는 악성코드의 경우는 이것들로 해결이 되지 않을 수 있다.


[시도-1] IceSword로 Process를 종료해보자.


(생성/종료를 반복하기 때문에 안보일때도 있음) 왼쪽메뉴 Function/Registry/File중 Function을 선택한 뒤 Process를 선택하면 실행중인 프로세스의 PathName과 ImageName를 확인할 수 있다. 마우스 우측버튼으로 선택해서 Terminate Process를 누르면 종료해보자. 종료된 것 처럼 보였지만, 여전히 프로세스 생성/종료를 반복하고 있다. 실패!!



[시도-2] 실패했다. 그러면 IceSword로 파일을 지워보자.


왼쪽메뉴 Function/Registry/File중 File을 선택하여 C드라이브를 선택하면 lsass.exe가 보이므로 해당 악성코드를 선택하여 [Delete]/[force delete]해보자. 지워진것 처럼 보이지만 Process Explorer에서는 여전히 실행/종료를 반복하고 있다. 실패!!



[시도-3] Gmer로 프로세스를 종료해보자.


(생성/종료를 반복하기 때문에 선택안됨) Gmer를 실행시키고 맨위의 메뉴 [Rootkit/Malware]/[>>>>]중 >>>>를 선택하면 아래와 같은 메뉴가 나온다. 그중 첫번째에 있는 Process를 선택하여 [Kill Process]하려 하였으나 선택이 안된다. 실패!!



[시도-4] Gmer로 파일을 파일을 지워보자.


메뉴중 [File]를 선택하여 C드라이브에 존재하는 lsass.exe를 선택하여 [Delete]를 누르면 제거되지만 다른 폴더를 억세스후 다시 확인해보면 그대로다. 실패!! [File]메뉴에도 [Kill]이 존재하여 종료해보니 성공 반!! 실패 반!! 이었다.



ㅂ. 왜 안되는지 문제점을 파악하자.


Process Explorer, IceSword의 문제는 실행/종료가 반복되는 해당 프로세스에 대한 종료를 하려 하면 이미 해당 프로세스의 ID(=PID)는 이미 사라지고 다른 PID가 생성되면서 딜레이가 발생해서 인것으로 추정되었다. 즉 툴이 보여주는 프로세스와 현재 실행중인 프로세스에 차이가 발생해서 종료가 불가능 했던 것이며, Gmer의 경우 성공 반!! / 실패 반!! 이 가능했던 이유는 변하지 않는 않는 파일쪽에서 [Kill]명령을 내려서 인것으로 추정되었다. 한 두번 하면 성공!!


ㅅ. 위의 방법만으로만 해결이 가능한 것일까? 좀더 쉬운 방법은 없을까?


여러가지 조건을 걸어줄 수 있는 Taskkill이 가능 했었다. 아래의 Process Explorer을 보면 정상 lsass.exe와 악성 lsass.exe의 차이를 찾아서 조건부 Kill을 하면 되는 것이었다. Process Explorer의 숨겨진 컬럼을 추가하여 보자.


a. View -> Select Columns선택



b. Process Image에서 User Name, command Line를 체크해준다.



c. 아래의 컬럼이 추가된 Process Explorer을 보면 User Name이 다른 것을 알수 있다.

Taskkill을 이용하여 종료시켜보자. 프로세스가 종료되는 순간이 있기 때문에 프로세스를 찾지 못하는 경우도 있으니, 한두번 더 해주면 성공할 것이다.

<<사용된 명령어>> Taskkill /f /fi “username eq pcname” /im lsass.exe




휴.. 해결되었다.. 처음엔 쉬운걸 선택한줄 알았는데, 의외로 까다로운 악성코드였다. 이번 악성코드는 좀 방황했지만, 대부분 Process Explorer에서 프로세스를 종료하고 IceSword나 Gmer로 파일을 지우면 대부분 해결된다. 이제 악성코드라고 멀리하지 말고 가끔은 자신의 힘으로 악성코드를 제거해보는건 어떨까 한다. 물론 가끔이다.


(주)하우리 기술연구소 바이러스팀 연구원 이새별


반응형
출처: http://www.devpia.com/DevStudy/Lecture/OffLineDetail.aspx?nSemiID=1429&lectype=evt

데브피아에 DB 튜닝관련 컬럼 연재가 올라왔네요. 내용이 괜찮아서 퍼왔습니다.

  필자가 처음에 SQL을 배울 때 SQL이 상당히 이상했다. 원하는 것만 요구할 뿐 어떻게 가져오라는 정보가 SQL에는 없었기 때문이다. FILE레벨의 I/O까지 코딩에 익숙한 필자에게 절차가 없다는 것이 오희려 더 이상했던 것이다.
물론 상세한 과정이 필요하지 않으므로 편리하고 좋았다 그러나 어떻게 가져오는지는 알지못하고 단지 사용할 뿐이었다.
그러나 SQL이 PLAN이라는 실행 계획을 만들고 그에 따라 가져오게 된다는 사실은 안것은 한참 뒤에 일이었다.
결국은 내가 하지않은 일을 Optimizer라는 프로그램이 대신 해주고 있는 것이 아닌가? 그래서 정말 고마운 놈이라고 생각했었다. 그러나 밑는 도끼에 발등을 찍힌다는 말이 있지 않은가?
Plan에 index를 달아주어도 Index를 사용하지 않고 full table scan만 하고 있으니 당체 속도가 나지를 않았다.
이래저래 해서 나중에 알게되었지만 결국 컬럼의 변형을 가하면 index를 사용하지 못한다는 것이다. 우리가 직접 사용하지는 않지만 결국 우리가 SQL을 사용한다는 것은 Optimizer라는 놈에게 SQL의 수행을 부탁하는 것이다. 따라서 우리가 Optimizer에 대해서 잘 안다면 SQL을 좀더 효율적으로 수행하도록 할 수 있지 않은가!
그러면 인덱스를 달았을 때 Optimizer가 index를 사용하지 못하는 경우를 통해서 우리가 애써(?)생성한 인덱시가 무용지물이 되지 않도록 해보자.
아래예제에 사용할 TABLE LAYOUT이다.
EMPLOYEES
---------
Rows=15,132
Empty Blocks=7
Chain Count=0
Avg Space Freelist Blocks=0
Sample Size=15,132
Partitioned=NO

Blocks=121
Avg Space=885
Avg Row Length=51
Freelist Blocks=0
Last Analyze=2009/05/04
Column Name
---------------
EMP_ID
MGR_ID
LAST_NAME
FIRST_NAME
HIREDATE
JOB
SALARY

Nullable
-----------------


NOT NULL
Column Type
-----------------
VARCHAR2(40)
VARCHAR2(40)
VARCHAR2(24)
VARCHAR2(14)
DATE
VARCHAR2(24)
NUMBER(7,2)
Distinct
-----------------
15,132
679
9,443
3,579
3,903
53
3,267
Buckets
------------------
75
75
75
75
75
53
75
INDEX
--------------------------------------------------------------------------------------
IDX_GENDER : GENDER
      Type=NORMAL, Uniq=No, Distinct=2, Rows=15,132, Last Analyze=2009/05/04
IDX_HIREDAT : HIREDATE
      Type=NORMAL, Uniq=No, Distinct=3,903, Rows=15,132, Last Analyze=2009/05/04
IDX_JOB : JOB
      Type=NORMAL, Uniq=No, Distinct=53, Rows=15,129, Last Analyze=2009/05/04
IDX_SALARY : SALARY
      Type=NORMAL, Uniq=No, Distinct=3,267, Rows=15,132, Last Analyze=2009/05/04
IDX_TYPE2 : TYPE
      Type=NORMAL, Uniq=No, Distinct=6, Rows=15,132, Last Analyze=2009/05/04
PK_EMP_ID : EMP_ID
      Type=NORMAL, Uniq=No, Distinct=15,132, Rows=15,132, Last Analyze=2009/05/04
필자가 여러군데 튜닝을 하면서 가장 많이 본것중에 하나는 INDEX를 달았으나 쓰지 못하게 되는 경우이다. 대표적인 경우가 아래와 같이 날짜타입(HIREDATE)에 TO_CHAR를 씌운 경우이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE TO_CHAR(HIREDATE,'YYYYMMDD') = '19980518';
물론 INDEX는 아래와 같이 생성되어있다.
CREATE INDEX IDX_HIREDATE ON EMPLOYEES(HIREDATE);
우리가 원하는 것은 INDEX를 타고 테이블을 가져오기를 바란것이었다.

그러나 실제 PLAN은 아래와 같이 나온다.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=28 Card=151 Bytes=3K)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=28 Card=151 Bytes=3K)
TABLE ACCESS (FULL) 이란 뜻은 INDEX를 타지 않고 테이블을 처음부터 끝까지 읽어서 찾는다는 뜻이다. 한마디로 10건이며 10건읽고 100만건이면 100만건을 다 읽어야 결과가 나온다는 말이다.

OPEN시에는 빠르던 시스템이 시간이 지날수록 느려지는 결정적인 역할을 하는 것이 바로 위와 같은 경우이다. 그럼 어떻게 해야 제대로 인덱스를 사용할 수 있을가?
일단 간단히 SQL의 수정으로 해결할수 있다. HIREDATE는 날짜 타입이다.
따라서 인덱스를 HIREDATE로 했을 때 인덱스를 타기위해서는 INDEX를 생성한것에 변형을 주어서는 안된다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE HIREDATE = TO_DATE('19980518')
따라서 간단하게 위와 같이 고치면 INDEX를 사용하게된다.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=4 Bytes=92)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEES' (TABLE) (Cost=3 Card=4 Bytes=92)
2 1 INDEX (RANGE SCAN) OF 'IDX_HIREDATE' (INDEX) (Cost=1 Card=4)
물론 결과도 빠르게 나온다 그러나 중요한 점이 있다 결과가 같을까?
운이 좋으면 결과가 같을 것이고 대부분의 경우는 결과가 틀리다.
왜 그럴까?
날짜 타입은 날짜와 시분초의 정보도 가지고 있다. 따라서 TO_DATE(‘19980518’)라는 말은 정확히 1998년5월18일 0시0분0초라는 뜻이다. 그래서 우리가 원하는 1998년5월18일자와는 차이가 있다.
따라서 1998년5월18일 0시0분1초 ~ 23시59분59초까지의 데이터는 나오지 않게되는것이다.
이것은 튜닝할 때 유의할 점이다. 결과를 같게 유지해야하는것이다. 이 상황을 알고있다면 방법은 간단하다.
아래아 같이 고치면 빠른시간에 원하는 결과를 얻을 수 있을 것이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE HIREDATE BETWEEN TO_DATE('19980518'||'00:00:00','YYYYMMDD HH24:MI:SS')
AND TO_DATE('19980518'||'23:59:59','YYYYMMDD HH24:MI:SS')
비슷하지만 함수의한 변형이 아닌 간단한 연산에의한 변형의 경우도 마찬가지이다.
$1000의 인센티브를 더주면 $10000이 넘는 사람을 찾는 SQL을 만들어보자.
아마 아래와 같을 것이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE SALARY + 1000 > 100000;
물론 INDEX는 아래와 같이 만들었다.
CREATE INDEX IDX_SALARY ON EMPLOYEES(SALARY);
그러나 PLAN을 보자
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=29 Card=757 Bytes=13K)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=29 Card=757 Bytes=13K)
인데스를 타지 못한다. 왜일까. 간단한 연산이지만 SALARY컬럼에 가공을 했기 때문에 OPTIMIZER는 인덱스를 타는 것을 포기해버린다.
따라서 우리가 기초적인 수학 실력을 발휘해서 이항을 해준다면 아래와 같은 조건이 될것이다.
SELECT FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE SALARY > 100000 - 1000;
이경우에 PLAN을 보자.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1 Bytes=17)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEES' (TABLE) (Cost=3 Card=1 Bytes=17)
2 1 INDEX (RANGE SCAN) OF 'IDX_SALARY' (INDEX) (Cost=2 Card=1)
재미 있게도 이번에 제대로 된 인덱스를 탄다. Optimizer가 바보 같다는 생각이 들지 않는가?
물론 바보같다. 그러나 OPTIMIZER나름대로 깊은 고민이 있다. 아주 잛은 시간내에 OPTIMIZER는 많은 경우의 수를 타진해야한다. 따라서 이항연산과 같은 것 까지 검토하면 너무 많은 시간을 소모하게 된다 따라서 그런부분은 포기한것이다.

또다른 경우중에 하나가 DB의 내부적인 변형이다. 이는 개발자가 의도하지 않게 문제를 야기하는 경우이다.
여기 PK 조건으로 검색하는 SQL이 있다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE EMP_ID = 200383;
그러나 PLAN은 아래와 같이 나왔다.
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=29 Card=1 Bytes=19)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=29 Card=1 Bytes=19)
분명히 아래와 같은 INDEX를 생성하였다.
CREATE INDEX PK_EMP_ID ON EMPLOYEES(EMP_ID);
왜 인덱스를 안타는 것일까?
그 이유은 OPTIMIZER의 내부 변형 규칙에 있다.
일반적으로 비교를 하려면 두개의 데이터 형이 같아야 한다.
그런데 EMP_ID는 VARCHAR2(40)이다 그리고 비교하려는 것은 200383이라는 숫자이다.
따라서 숫자와 문자는 비교할수 없기 때문에 내부적으로 변형이 이루어진다.
문자보다 숫자가 우선순위가 높아서 문자와 숫자를 비교하게되면 문자쪽이 숫자로 변형되어 비교하게 되는 것이다.
따라서 위의 SQL은 OPTIMIZER는 아래와 같은 SQL로 수행하게된다.
EMP_ID를 TO_NUMBER(EMP_ID) = 2000393과 같이 처리하게 된다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE TO_NUMBER(EMP_ID) = 200383;
이는 처음 예제에서 날짜 컬럼에 TO_CHAR를 씌원것과 같은 효과이다. 따라서 이문제를 해결하기위해서는 반대쪽, 즉 2000293을 문자로 변환해주면 문자대 문자의 비교이므로 내부적 변형이 발생하지 않게된다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE EMP_ID = ‘200383’;
 
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=1 Bytes=19)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMPLOYEES' (TABLE) (Cost=2 Card=1 Bytes=19)
2 1 INDEX (RANGE SCAN) OF 'PK_EMP_ID' (INDEX) (Cost=1 Card=1)
아래 SQL을 보자 JOB에 NULL인 조건을 검색하는 것이다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE JOB IS NULL
아래 SQL을 보자 JOB이 NULL인 조건을 검색하는 것이다.
물론 아래와 같은 JOB INDEX를 생성하였다.
CREATE INDEX IDX_JOB ON EMPLOYEES (JOB);
아래 PLAN을 보자 왜 IDX_JOB INDEX를 타지 못하는가?
Execution Plan
--------------------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=29 Card=3 Bytes=63)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=29 Card=3 Bytes=63)
이경우에는 Oracle의 경우 일반적으로 index를 생성할 때 null값은 index항목에 넣지 않는다. 따라서 null은 index에 없기 때문에 null조건을 준다면 그것은 index를 탈수 없다.
따라서 위와 같은 경우 반드시 index를 타려거든 job컬럼을 NOT NULL로 설정하고 NUL대신 특정값 (예를 들면 : ‘NOT ASSIGN’ ) 으로 설정하고 QUERY를 아래와 같이 수정한다면 인덱스를 탈수 있을 것이다.
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE JOB = ‘NOT ASSIGN’;
아래 SQL를 하나 더 보자
SELECT LAST_NAME,FIRST_NAME
FROM EMPLOYEES
WHERE JOB NOT IN ( 'INSTRUCTOR','STAFF');
이번의 NULL을 비교한것도 아닌데 INDEX를 사용하지 못한다. 이것은 일반적인 INDEX가 =이나 <, > , BETWEEN조건에 만 인덱스를 탈수 있고 부정형으로 비교했을때는 인덱스를 탈수 없기때문이다.
생각해보자 어떤 것을 순서대로 정리해 놓았는데 그것이 아닌 것을 찾으려고 한다면 전체를 다 읽어봐야지만 아니것을 알수 있지 않은가?
따라서 가급적 프로그램 구성에서 부정형 조건이 들어가게 한다는 것은 성능을 저하시킬 가능성이 매우 높기 때문에 이런 조건이 되지 않도록 설계단설계부터 고려해야한다.

이상은 간단하게 INDEX를 주었을 때 일반적으로 INDEX를 타지 못하는 경우를 든것이다. 사실 위예 예처럼 실제 프로젝트에서 많은 부분이 INDEX를 생성하고도 OPTIMIZER의 특성을 몰라서 INDEX를 쓰지 못한채 APPLICATION이 돌고 있다. 이는 곧바로 자원의 과도 사용으로 나타나고 느린 응답시간으로 나타나게 된다. 항상 시스템을 OPEN하고 마음을 조리지 않으려면 내가 생성된 INDEX를 잘 탈수 있게 내가 SQL을 잘 작성했는지 검토해 보기 바란다.
아래 4개의 항목은 반드시 기억해 두기 바란다.
인덱스를 사용하지 못하는 경우는 아래와 같다.
  • 인덱스 컬럼에 변형이 일어난 경우
    • WHERE TO_CHAR(HIREDATE,'YYYYMMDD') = '19980518';
    • WHERE SALARY + 1000 > 100000;
  • 내부적인 변형이 일어난 경우
    • WHERE EMP_ID = 200383;
  • NULL을 비교하였을 경우
    • WHERE JOB IS NULL;
  • 부정형으로 조건을 기술한 경우
    • WHERE JOB NOT IN ( 'INSTRUCTOR','STAFF');

물론 이 경우 이외에 Optimizer의 판단에 따라서 인덱스를 사용하지 못하는 경우도 있다. 그러나 대부분의 경우에는 위에 항목을 만족한다면 원하는 index를 타는 효율적인 sql작성에 좋은 기준이 될것이다. 마지막으로 sql을 작성한후 반드시 plan을 확인해 보기 바란다.
실제 plan이 어떻게 되는냐를 확인해보지 않으면 무심코 과거의 실수를 답습할 수 있기때문이다.



+ Recent posts