[Java]갑자기~ 자바 네트워크 Sniffer 64비트 용

2022. 12. 25. 19:22프로그래밍

728x90

갑자기 코드프로젝트에서 눈에 띄어서 번역한 글을 보다가..

자바도 pcap 같은 라이브러리가 있을 것 같아서 찾아 보았습니다.

가장 눈에 띄는 링크를 클릭 해 보았더니,

https://www.codewithc.com/network-packet-sniffer-java-project/

 

Network Packet Sniffer Java Project | Code with C

Network Packet Sniffer project developed in Java, monitors traffic over a network. Download source code and project synopsis.

www.codewithc.com

 

궁금증이 생겨서 그냥 이클립스에서 돌려 보았습니다.

돌려보니까 뭐.. 안돌아가네요

 

소스를 다 이어 붙혀버렸습니다.

 

 

아...그리고 나면 이제 네이티브 컴파일이 남겠네요.

그냥 주어진 대로, 32비트로 컴파일 해볼까 합니다. JNI 경로를 내것으로 맞추어 주었습니다.

(JNI가 뭔지 모르신다면... 좀 더 알아보시면 됩니다. )

 

오류가 납니다. 재 정의 문제가 일어나는 데요...

pcap.h 순서를 다음과 같이 바꾸고

#ifndef lib_pcap_h
#define lib_pcap_h

#include <stdio.h>

#if defined(WIN32)
  #include <pcap-stdinc.h>
#elif defined(MSDOS)
  #include <sys/types.h>
  #include <sys/socket.h>  /* u_int, u_char etc. */
#else /* UN*X */
  #include <sys/types.h>
  #include <sys/time.h>
#endif /* WIN32/MSDOS/UN*X */

#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H
#include <pcap-bpf.h>
#endif
/*#include <stdio.h>*/
 

pcap-stdinc.h 헤더 파일을 다음과 같이 바꿔 주었습니다.

#ifndef vsnprintf
#define snprintf _snprintf
#endif

#ifndef vsnprintf
#define vsnprintf _vsnprintf
#endif
 

그런다음에 빌드 해 줍니다. 그러면 다음 디렉토리에 Jpcap.dll 이 생기게 되죠...

이게 끝이라면, 삽질이라고 하지는 않았겠죠? 이제부터 시작이라고 말은 못해도 뭐 여하튼..

다시 자바로 돌아가서 위 dll 을 맞춰 볼 시간 입니다.

위 dll 을 자바로 넣어 볼려면 혹은 구동 해 볼려면, 다음의 링크에 소스코드를 얻어 와야 합니다.

https://blog.naver.com/tommybee/221998813223

 

런타임 상에서 자바 라이브러리 경로 바꾸기

런타임 상에서 자바 라이브러리 경로 바꾸기 #자바 의 #시스템 #프로퍼티 인 java.library.path는 네이티브...

blog.naver.com

 

메인 메서드가 아래 처럼 변해야 겠죠...

public static void main(String[] args){
		
	try{
        //둘 중 하나만 쓰면 됩니다.
		//setLibraryPath("C:/DEV/LIBS/jpcap-master/src/c/win32/Release/");
		addLibraryPath("C:/DEV/LIBS/jpcap-master/src/c/win32/Release/");
		
		//System.setProperty("java.library.path", "C:/DEV/LIBS/jpcap-master/src/c/win32/Release/");
		System.loadLibrary("Jpcap"); 
		
	}catch(Exception e){
		JOptionPane.showMessageDialog(null,"Cannot find Jpcap. Please download and install Jpcap before running.");
		System.exit(0);
	}
	
	try{
		Class<?> c=Class.forName("jpcap.JpcapCaptor");
	}catch(ClassNotFoundException e){
		JOptionPane.showMessageDialog(null,"Cannot find Jpcap. Please download and install Jpcap before running.");
		System.exit(0);
	}
			
	PacketAnalyzerLoader.loadDefaultAnalyzer();
	StatisticsTakerLoader.loadStatisticsTaker();
	loadProperty();
	
	openNewWindow();
	
}
 

그러고 나면, 다음 오류가 나고 있네요...ㅡ.ㅡ;;

Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\DEV\LIBS\jpcap-master\src\c\win32\Release\Jpcap.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
	at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
	at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
	at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
	at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
	at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2649)
	at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:827)
	at java.base/java.lang.System.loadLibrary(System.java:1871)
	at netpacsniff.NetPackSniff.main(NetPackSniff.java:75)
 

와우~ 멋지네요.. 다시 C로 돌아가야 하나요???

아니면, 32비트 용으로 자바를 다시 받는 것도 되겠지만...

검색이 최고 겠죠? 감사의 편지라도 써야 할 것 같아요...

https://github.com/jovigb/jpcap-x64

 

GitHub - jovigb/jpcap-x64: sniffer capture network packet supoort x64 on win7

sniffer capture network packet supoort x64 on win7 - GitHub - jovigb/jpcap-x64: sniffer capture network packet supoort x64 on win7

github.com

 

이 글 처음으로 돌아가서 다시 초심으로 여기까지 오면 될 것 같습니다.

메인 메서드 소스를 다시 맞추고...

try{
	//setLibraryPath("C:\\DEV\\LIBS\\jpcap-x64-master\\src\\c\\win32\\x64\\Release\\");
	addLibraryPath("C:\\DEV\\LIBS\\jpcap-x64-master\\src\\c\\win32\\x64\\Release\\");
	
	//System.setProperty("java.library.path", "C:/DEV/LIBS/jpcap-master/src/c/win32/Release/");
	System.loadLibrary("Jpcap"); 
	
}catch(Exception e){
	JOptionPane.showMessageDialog(null,"Cannot find Jpcap. Please download and install Jpcap before running.");
	System.exit(0);
}
 

다시 진행을 해보면, 다음과 같이 GUI 뜨는 것을 확인 해 볼 수 있습니다.

잘 모르면 젤 눈에 띄는 화살표를 한번 눌러볼까요

 

 

 

뭔지 모르겠지만, 사람의 호기심을 자극하는 화면이 뜨네요...

내 네트워크 카드를 선택하고 나서

 

 

 

OK 하면...ㅎㅎㅎ 또 오류가 나네요

 

setPacketValue 라...

 

JpcapCaptor captor;
NetworkInterface[] list;
String str,info;
int x, nChoice;

int nCountPacket = 0;
		
public static void main(String args[]) {
	
	try{
		//NetPackSniff.setLibraryPath("C:\\DEV\\LIBS\\jpcap-x64-master\\src\\c\\win32\\x64\\Release\\");
		NetPackSniff.addLibraryPath("C:\\DEV\\LIBS\\jpcap-x64-master\\src\\c\\win32\\x64\\Release\\");
		
		//System.setProperty("java.library.path", "C:/DEV/LIBS/jpcap-master/src/c/win32/Release/");
		System.loadLibrary("Jpcap"); 
		
	}catch(Exception e){
		JOptionPane.showMessageDialog(null,"Cannot find Jpcap. Please download and install Jpcap before running.");
		System.exit(0);
	}
	
	new NetPackSniffConsole();
}

public NetPackSniffConsole() 
{

	list = JpcapCaptor.getDeviceList();
	System.out.println("Available interfaces: ");
		
	for(x=0; x<list.length; x++) {
		System.out.println(x+" -> "+list[x].description);  
	}
	
	System.out.println("-------------------------\n");
	nChoice = Integer.parseInt(getInput("Choose interface (0,1..): "));
	System.out.println("Listening on interface -> "+list[nChoice].description);
	System.out.println("-------------------------\n");
	  
	/*Setup device listener */
	try {
		captor=JpcapCaptor.openDevice(list[nChoice], 65535, false, 20);
		 /* listen for TCP/IP only */
		captor.setFilter("ip and tcp", true);
	} catch(IOException ioe) { ioe.printStackTrace(); }
	  
	  
	/* start listening for packets */
	while (true) { 
		Packet    info = captor.getPacket();
		
		if(info != null){
			String sData = getPacketText(info);
		 System.out.print(sData);
		}
	}
} 

/* get user input */
public static String getInput(String q) 
{
	String input = "";
	System.out.print(q);
	BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in));
	try {
		input = bufferedreader.readLine();
	} catch(IOException ioexception) { }
	
  return input;
}
  
 
 /* return packet data in true text */
String getPacketText(Packet pack)
{   
 
	int i=0,j=0;
	
	// Data (Payload)만 출력
	byte[] bytes=new byte[pack.data.length];
	System.arraycopy(pack.data, 0, bytes, 0, pack.data.length);
	
	//--------------------------------------------------------------------
	// 캐스팅한번하면 Packet  클래스가 깨진다. 왜그런지는 모르겠다. --> 패키지특징내지 버그같음..
	//--------------------------------------------------------------------
	String sPackInfo = ""; 
	if( pack.data.length > 0){
		sPackInfo = "SRC:" +  ((IPPacket)pack).src_ip + "\r\n" + "DST:" +  ( (IPPacket)pack).dst_ip;
		sPackInfo += "\r\n" + ShowHex(bytes.length, bytes);
	}
	
	return sPackInfo;
}
	   
	   
// Hex 출력
private String ShowHex(int nSize, byte[] pData)
{
	final int DISPLAY_COUNT = 16;
	final int MAX_SIZE      = 1024 * 15; // 최대보여지는개수 
	
	String msg      = "";
	String sTmp     = "";
	String sTmp2    = "";
	String sLineNum = "";
 
	int nLineNum = 0;
	 
	msg  = "0000:"; 
	
	if(nSize > MAX_SIZE) nSize = MAX_SIZE; 
			
	for(int i = 1; i < nSize + 1; i++){
		sTmp  = sTmp.format("%02X ", pData[ i - 1 ] );
		if(( pData[ i - 1] < 127) && ( pData[ i - 1] > 32)){
			sTmp2 += sTmp2.format("%c", pData[ i - 1 ] );
	 
		} else {
			sTmp2 += ".";
		}
		
		if(i % DISPLAY_COUNT  == 0 && i != 1){
			msg += sTmp;
		 
			msg += " ";
			msg += sTmp2;
		 
			msg += "\r\n";
		 
			sTmp2 = "";
			
			msg += sLineNum.format("%04X:", nLineNum += DISPLAY_COUNT); 
			
		} else if(i == nSize && i % DISPLAY_COUNT != 0 ){ 
			int nEmtSpace = DISPLAY_COUNT - (i % DISPLAY_COUNT);
			for(int j = 0; j < nEmtSpace; j++){
			 sTmp += "   "; 
			}
			msg += sTmp;
			msg += " ";
			msg += sTmp2;
			msg += "\r\n";

		} else { 
			msg += sTmp;
		} 
	}
 
	if ( nSize == 0 ) msg = "";
	return msg;
}
 

똑같은 오류 메시지를 뱉고 있네요...

 

음... 그래서 머리로 생각을 좀 해보기로 했죠.

메서드가 없다는 것은 C 에서 호출 한 것이겠구나 하고요. 해당 이름으로 찾아 보니 다음과 같은 인터페이스가 있네요

setPacketValueMID=(*env)->GetMethodID(env,Packet,"setPacketValue",
					"(JJII)V");
 

Packet 은 다음과 같이 정의 하였네요

GlobalClassRef(Packet,"jpcap/packet/Packet");
 

그리고 해당 메서드를 자바에서 찾아보면,

void setPacketValue(long sec, long usec, int caplen, int len, int processid, String process) {
	this.sec = sec;
	this.usec = usec;
	this.caplen = caplen;
	this.len = len;
	this.processid = processid;
	this.process = process;
}
 
 

아래 시그너쳐의 변환은

"(JJII)V" ==> (long, long, int, int )
 

인 반환값이 없는 메서드가 되겠죠. 그럼 위에 메서드를 하나 복사해서 다음과 같이 만들어 보겠습니다. 수정 하는 것은 능력도 안되고 귀찮기도 하고 그리고 개발자의 의도도 잘 모르겠네요...

코드로 보아 프로세스 아이디랑 프로세스를 찾을려고 했던 것 같은데 음...과연 그럴까 싶기도하고요.

void setPacketValue(long sec, long usec, int caplen, int len) {
	this.sec = sec;
	this.usec = usec;
	this.caplen = caplen;
	this.len = len;
	this.processid = 0;
	this.process = "N/A";
}
 

그럼 부푼 꿈을 안고 다시 실행 시켜봅니다. 그런데 가만 생각해 보니 우리집에서 Wi-Fi 를 사용하고 있다는 것을 깜박했네요^^;;

 

Microsoft 가 세개, 랜카드가 한개가 나오네요

내 컴터의 네트워크는...이렇게 되어 있습니다.

그래서 아무 Microsoft 를 눌러 보았어요.

음... 무엇을 표현하려고 했는 지는 소스를 찬찬히 띁어 보아야 하겠네요.

원래 사이트의 이미지는 이런 것이었는 데...

현실과 이상의 차이가 넘 크네요...

위에서 언급한 콘솔 프로그램은 나오질 않는 거 보니 API가 약간 바뀐듯 하네요...

 

정신 건강에 안좋으니 그만 접어야 할 것 같습니다.

잘 된 것도 아니고, 안 된것도 아니고 ... 찝찝하네요~^^;;

그렇다고 남의 작품을 나쁘다고 하는 것은 아니고, 네트워크에 대해서 깊숙히 알지 못해서 나온 얘기라고 생각 해 주세요~

 

 

 

이상.

 

부록. jpacp64비트 dll과 소스코드

728x90