ソースコード

シー | シェルコードローダー

シェルコードローダー シェルコードをテストするためのシンプルなコマンドライン ツールです。
C言語で書かれており、オープンソースで提供されています。
WinXP から Win10 までのすべての Windows で動作します。

シェルコードローダー

そのページでの詳細情報とダウンロード

C++ & Delphi | | CryptoGear 暗号化アルゴリズム

BreakingSecurity が開発した対称鍵ブロック暗号。

ここで C++ 実装を見つけることができます.
あなたはそのを見つけることができます Delphi ここでの実装.

C++ | RC4クラス

スタンダード RC4 暗号化アルゴリズム.
シンプルで高速なこのアルゴリズムは、多くのアプリケーションで使用されている有名なアルゴリズムです。

cRC4.h :

/***********************************************************
* Standard RC4 Encryption
* C++ Class
* Coded by Viotto © BreakingSecurity.net
***********************************************************/
#include <string>
using namespace std;
class CRC4
{
public:
	CRC4(unsigned char* pKey, unsigned int lenKey);
	CRC4();
	void RC4(unsigned char pData[], unsigned long lenData);
	string RC4Str(unsigned char* pInputData, unsigned long InputSize);
	void Initialize(unsigned char* pKey, unsigned int lenKey);
private:
	int m_sBox[256]; //substitution-box
	int a, b;	
	unsigned char swap;
};

 

cRC4.cpp :

/***********************************************************
* Standard RC4 Encryption
* C++ Class
* Coded by Viotto © BreakingSecurity.net
***********************************************************/

#include "cRC4.h"
// Constructor. It will generate s-box based on the provided key.
// This way future encryption/decryptions routines will not have to recreate s-box each time.
CRC4::CRC4(unsigned char* pKey, unsigned int lenKey)
{
	Initialize(pKey, lenKey);
}
/* Overloaded costructor with no arguments.
   Must initialize s-box manually.           */
CRC4::CRC4()
{}

void CRC4::Initialize(unsigned char* pKey, unsigned int lenKey)
{
	// Initialize substitution box, based on the provided key.
	b = 0;
	for (a = 0; a < 256; a++)
	{
		m_sBox[a] = a;
	}
	for (a = 0; a < 256; a++)
	{
		b = (b + m_sBox[a] + pKey[a % lenKey]) % 256;
		swap = m_sBox[a];
		m_sBox[a] = m_sBox[b];
		m_sBox[b] = swap;
	}
}

void CRC4::RC4(unsigned char pData[], unsigned long lenData)
{
	int sBox[256];
	int i = 0, j = 0;
	long Offset;
	// Create a local copy of the s-box. Better than recreating each time before encrypting/decrypting.
	memcpy(sBox, m_sBox, 256 * sizeof(int));
	//Encrypt the data
	for (Offset = 0; Offset < lenData; Offset++)
	{
		i = (i + 1) % 256;
		j = (j + sBox[i]) % 256;
		swap = sBox[i];
		sBox[i] = sBox[j];
		sBox[j] = swap;
		pData[Offset] ^= sBox[(sBox[i] + sBox[j]) % 256];
	}
}

// This function does not overwrite input with output, but saves it on a separate string.
string CRC4::RC4Str(unsigned char* pInputData, unsigned long InputSize)
{
	string sInputOutputData((char*)pInputData, InputSize);
	RC4((unsigned char*)sInputOutputData.c_str(), InputSize);
	return sInputOutputData;
}
シー | カーネル レベルで PID からプロセス パスを取得する

ユーザー レベルでは、GetModuleFileNameEx() などの API を使用することで、このような単純なタスクを簡単に行うことができます。

ただし、カーネルレベルでそれを行う方法は文書化されていません。
多くの人がそれを求めているのを見つけましたが、明確に機能するスニペットが見つからなかったので、私のものを共有すると役立つと思いました.

 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
BOOLEAN KrnGetProcessPath(HANDLE hProcessId)
// ProcessID handle can be get using PsGetCurrentProcessId(),
// or by using process callback routines such as PsSetCreateProcessNotifyRoutine()
{
	HANDLE hProcess = NULL;
	OBJECT_ATTRIBUTES obj_attr;
	CLIENT_ID cid;
	cid.UniqueProcess = hProcessId; 
	cid.UniqueThread = NULL;
	InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
	ZwOpenProcess(&hProcess, GENERIC_READ, &obj_attr, &cid);
	// When the ProcessInformationClass parameter is ProcessImageFileName, 
	//	the buffer pointed to by the ProcessInformation parameter should be large enough to hold a UNICODE_STRING structure, 
	//	as well as the string itself.
	WCHAR ustrBuffer[(sizeof(UNICODE_STRING) / sizeof(WCHAR)) + 260];
	UNICODE_STRING ustrPath;
	// Initialize UNICODE_STRING
	ustrPath.Buffer = ustrBuffer;
	ustrPath.Length = 0x0;
	ustrPath.MaximumLength = sizeof(ustrBuffer);
	// Process path will be saved inside the unicode string.
	NTSTATUS ret = ZwQueryInformationProcess(hProcess, ProcessImageFileName, &ustrPath, sizeof(ustrBuffer), NULL);
	if (NT_SUCCESS(ret))
	{
		DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "[DEBUG] process path: %wZ\n", ustrPath);
		return TRUE;
	}
	else
	{
		DbgPrintEx(DPFLTR_IHVDRIVER_ID, 0, "[ERROR] error getting process path: %x\n", ret);
		return FALSE;
	}
}
シー | LoadDll: LoadLibrary の代替

次のコードは、Windows の LoadLibrary() 関数を置き換えるもので、アドレス空間に DLL をロードする別の方法です。

 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
#include <Windows.h>
// UNICODE_STRING structure
typedef struct _UNICODE_STRING 
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
//LdrLoadDll function prototype 
typedef NTSTATUS (WINAPI *fLdrLoadDll) 
(
	IN PWCHAR PathToFile OPTIONAL,
	IN ULONG Flags OPTIONAL, 
	IN PUNICODE_STRING ModuleFileName, 
	OUT PHANDLE ModuleHandle 
); 
//RtlInitUnicodeString function prototype
typedef VOID (WINAPI *fRtlInitUnicodeString) 
(
	PUNICODE_STRING DestinationString,
	PCWSTR SourceString
);
HMODULE hNtDll;
fLdrLoadDll _LdrLoadDll;
fRtlInitUnicodeString _RtlInitUnicodeString;
//_____________________________________________
//
// LoadDll: LoadLibrary replacement
// 
// This function loads the specified DLL into our process.
// This function is a replacement for the Windows LoadLibrary() function. 
//
// PARAMETERS:
// szFileName: path of the DLL to load.
//
// RETURN VALUE:
// HMODULE DllHandle: An handle to the DLL module in memory.
//_____________________________________________
//
HMODULE LoadDll( LPCSTR szFileName) 
{  
   // Load required functions dinamically
   hNtDll = GetModuleHandleA("ntdll.dll");
   _LdrLoadDll = (fLdrLoadDll) GetProcAddress( hNtDll, "LdrLoadDll");
   _RtlInitUnicodeString = (fRtlInitUnicodeString) GetProcAddress( hNtDll, "RtlInitUnicodeString");
   int StrLen = lstrlenA(szFileName);
   BSTR WideStr = SysAllocStringLen(NULL, StrLen);
   MultiByteToWideChar(CP_ACP, 0, szFileName, StrLen, WideStr, StrLen);
   UNICODE_STRING usDllName;
   _RtlInitUnicodeString(&usDllName, WideStr);
   SysFreeString(WideStr);
   HANDLE DllHandle; 
   _LdrLoadDll(0, 0, &usDllName, &DllHandle);
   return (HMODULE)DllHandle;
}
int main() //Usage example
{
   HMODULE hmodule = LoadDll("Kernel32.dll");
   return (int)hmodule;
}

C++ | ファイル検索

ファイル名またはその一部を検索するために使用できるシンプルで高速な再帰関数。
指定したフォルダとそのすべてのサブディレクトリ内。

 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
#include <windows.h>
#include <algorithm>
#include <string>
using namespace std;
//_____________________________________________
//
// FileSearch Function
// 
// This function will search for a filename or part of it,
// inside the specified directory and in all of the subdirectories.
// © BreakingSecurity.net
//
// PARAMETERS:
// sSearch: String which specifies a filename, or a part of filename to be searched for.
// sDir: Path to search in (ex: "C:\\Windows")
//_____________________________________________
//
bool FileSearch(string sSearch, string sDir)
{
	// Convert all characters to lowercase
	std::transform(sSearch.begin(), sSearch.end(), sSearch.begin(), ::tolower);
	
	// Check for final slash in path and append it if missing
	if (sDir[sDir.length() -1] != '\\')
	{
		sDir += "\\";
	}
	
	WIN32_FIND_DATA FileInfo;
	HANDLE hFind = FindFirstFileA(string(sDir + "*").c_str(), &FileInfo);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		FindClose(hFind);
		return false;
	}
	string sFileInfo;
	while (FindNextFile(hFind, &FileInfo) != 0)
	{
		if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
			&& strcmp(FileInfo.cFileName, ".") != 0
			&& strcmp(FileInfo.cFileName, "..") != 0)
		{
			// Recursive seach inside subdirectory
			string sRecursiveDir = sDir + string(FileInfo.cFileName);
			FileSearch(sSearch, sRecursiveDir);
		}
		
		string sFileName(FileInfo.cFileName);
		
		// Convert all characters to lowercase
		std::transform(sFileName.begin(), sFileName.end(), sFileName.begin(), ::tolower);
		
		// Check if filename contains search string
		if (sFileName.find(sSearch) != string::npos)
		{
			//Search string has been found inside file name
			printf(string(sDir + FileInfo.cFileName + "\n").c_str());
		}
	}
	FindClose(hFind);
	return true;
}
// Usage example:
// FileSearch.exe "Notepad" "C:Windows"
void main(int argc, char* argv[])
{
	if (argc == 3)
	{
		FileSearch(argv[1], argv[2]);
		printf("Search finished!\n");
	}
	else printf("Wrong number of parameters\n");
	system("pause");
}

C++ | Viotto .OCX登録者

Viotto OCX Registrator は、インストール、登録、および登録解除を行うためのシンプルなツールです OCX ファイル.
無料でオープンソースで公開されています。
Embarcadero C++ でコーディングされています。
あなたはそれを見つけることができます (詳細を見る)。.

Delphi | | Windows 名前付きパイプを使用したプロセス間通信

このサンプルは、異なるプロセス間で通信し、データを交換する方法を示すことを目的としています。
素晴らしい記事を書いてくれた Peter Bloomfield に感謝します。 C++ での Windows パイプに関するチュートリアル.
program PipeServer;
// Server application which creates an inbound pipe and waits for data from client processes.
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Windows;
procedure ReceivePipeData();
var
  pipe: Cardinal;
  RecBuffer: Array[0..999] of Byte;
  numBytesRead: DWORD;
  result: LongBool;
  sReadData: AnsiString;
  sa: SECURITY_ATTRIBUTES;
  sd: SECURITY_DESCRIPTOR;
begin
  // Must grant access rights in case User Account Control is on, on WinVista and above,
  // and communicating processes are under a different user (which can be also SYSTEM).
  // Otherwise, the other side of the pipe will receive ERROR_ACCESS_DENIED upon CreateFile().
  // If UAC is on and we are trying to use pipe between a userlevel and a system process,
  // even if we are inside the same user account, pipe communication will fail.
  // In order to avoid this, we must initialize a security descriptor for the pipe.
  InitializeSecurityDescriptor(@sd, SECURITY_DESCRIPTOR_REVISION);
  // There is an important difference between an empty and a nonexistent DACL.
  // When a DACL is empty, it contains no access control entries (ACEs); therefore, no access 
     rights are explicitly granted.
  // As a result, access to the object is implicitly denied.
  // When an object has no DACL (when the pDacl parameter is NULL),
  // no protection is assigned to the object, and all access requests are granted.
  SetSecurityDescriptorDacl(@sd, True, nil, False);
  sa.bInheritHandle := false;
  sa.lpSecurityDescriptor := @sd;
  sa.nLength := sizeof(sa);
  while true do begin
    repeat
      // Create a new pipe to receive data
      pipe := CreateNamedPipe(
         '\.pipeSamplePipe', // Our pipe name
         PIPE_ACCESS_INBOUND, // Read-only pipe
         PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE, //Using Message mode
         PIPE_UNLIMITED_INSTANCES ,
         0,  // No outbound buffer
         0,  // No inbound buffer
         0,  // Use default wait time
         @sa // Set security attributes to grant access rights
      );
      if (pipe = INVALID_HANDLE_VALUE) then begin
        Write('[ERROR] Failed to create pipe. Error code ' + IntToStr(GetLastError()) + #13#10 + 
              'Press Enter to retry');
        Readln;
      end;
    until pipe <> INVALID_HANDLE_VALUE;
    WriteLn('[INFO] Inbound pipe created! Waiting for a client process to connect...');
    // This call blocks until a client process connects to the pipe
    result := ConnectNamedPipe(pipe, nil);
    if (result = false) then begin
      Writeln('[ERROR] Failed to connect to pipe. Error code ' + IntToStr(GetLastError()));
    end
    else begin
      Writeln('[INFO] Client connected! Waiting for data...');
      numBytesRead := 0;
      // The read operation will block until there is data to read
      result := ReadFile(
          pipe,
          RecBuffer[0], // The data from the pipe will be put here
          sizeof(RecBuffer), // Number of bytes allocated
          numBytesRead, // This will store number of bytes actually read
          nil // Not using overlapped IO
      );
      if (result = false) then begin
          Writeln('[ERROR] Failed to read pipe data! Error code ' + IntToStr(GetLastError()));
      end else begin
          SetString(sReadData,PAnsiChar(@recBuffer[0]), numBytesRead); //Copy byte array to string
          Writeln('[SUCCESS] Data received: ' + sReadData);
      end;
    end;
    //Close our pipe handle
    CloseHandle(pipe);
  end;
end;
//Program start procedure
begin
  Writeln('*** Pipe Server Application ***' + #13#10);
  Write('[INFO] Press Enter to create pipe server and start listening for incoming data');
  ReadLn;
  ReceivePipeData();
end.
program PipeClient;
// Client application which sends data to pipe server.
{$APPTYPE CONSOLE}
uses
SysUtils,
Windows,
Classes;
// Data to send via pipe is read from a file.
function GetDataFromFile(sFileName: AnsiString): AnsiString;
var
DataFile: TFileStream;
ReadBuffer: array of Byte;
sDataToSend: AnsiString;
begin
  try
    DataFile := TFileStream.Create( sFileName , fmOpenRead);
    SetLength(ReadBuffer, DataFile.Size);
    DataFile.Read(ReadBuffer[0], Length(ReadBuffer));
    SetString(sDataToSend,PAnsiChar(@ReadBuffer[0]), DataFile.Size); //Copy byte array to string
    DataFile.Free;
    Result := sDataToSend;
  except
    Result := '';
  end;
end;
procedure SendPipeData();
var
pipe: Cardinal;
numBytesWritten: DWORD;
result: LongBool;
sDataToSend: AnsiString;
begin
  repeat
    // Open the named pipe, previusly created by server application
    pipe := CreateFile(
    '\.pipeSamplePipe', // Our pipe name
    GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE,
    nil,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0
    );
    if (pipe = INVALID_HANDLE_VALUE) then begin
      Write('[ERROR] Failed to open pipe (server must be running first).' + #13#10 + 'Press Enter to 
      retry');
      Readln;
    end;
  until pipe <> INVALID_HANDLE_VALUE;
  repeat
    //Get data to send from file
    sDataToSend := GetDataFromFile(ExtractFilePath(ParamStr(0)) + 'DataToSend.txt');
    if sDataToSend = '' then begin
      Write('[ERROR] Unable to read data from file (may be unexistent or empty).' + #13#10 + 'Press
      Enter to retry');
      Readln;
    end;
  until sDataToSend <> '';
  numBytesWritten := 0;
  result := WriteFile(
  pipe, // Handle to our outbound pipe
  sDataToSend[1], // Pointer to data to send
  Length(sDataToSend), // Length of data to send (bytes)
  numBytesWritten, // Will store actual amount of data sent
  nil // Not using overlapped IO
  );
  if (result = false) then
    Writeln('[ERROR] Failed to send pipe data. Error code ' + IntToStr(GetLastError()))
  else Writeln('[SUCCESS] Pipe data sent: ' + sDataToSend);
  // Close the pipe handle
  CloseHandle(pipe);
end;
//Program start procedure
begin
  Writeln('*** Pipe Client Application ***' + #13#10);
  while true do begin
    Write('[INFO] Press Enter to send pipe data to server');
    Readln;
    SendPipeData();
  end;
end.

VB6 | Viotto Binder

見つけることができます Viotto Binder 独自のページのソース (詳細を見る)。.

VB6 | フォームレス ファイル ダイアログ: OCX/フォーム/コンポーネントは必要ありません!

この単純なクラスを使用すると、フォームを必要とせずに FileDialog を作成できます。フォーム上で comdlg32.OCX とそのビジュアル CommonDialog コンポーネントを使用する必要もありません。

また、OCX コンポーネントを使用する場合よりもパフォーマンスが向上します。
右側のスクリーンショットは、FileDialog を開いたときのパフォーマンスの違いを示しています。左側は従来の OCX CommonDialog コントロール、右側はこのコードを使用した直接 DLL 呼び出しです。

' cFileDialog.cls
' by Viotto - www.BreakingSecurity.net
'
' Provides CommonDialog functionality,
' without the need of ocx file and graphical component.
'
' ComDlg32.OCX provides an easy-to-use interface, but if you use the OCX control,
' you have to load the module into memory and also distribute a 90K OCX file to users of your software.
' To improve performance, and eliminate the need of additional dependencies,
' you should minimize the use of controls in your applications.
' Instead, you can use the Win32 API calls directly.
'
' More info from Microsoft: https://support.micr...en-us/kb/161286
 
 
Option Explicit
 
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
  "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
  
Private Declare Function GetSaveFileName Lib "comdlg32.dll" Alias _
  "GetSaveFileNameA" (pOpenfilename As OPENFILENAME) As Long
  
Private Declare Sub CopyMemory Lib "kernel32" Alias _
  "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
 
Private Type OPENFILENAME
  lStructSize As Long
  hwndOwner As Long
  hInstance As Long
  lpstrFilter As String
  lpstrCustomFilter As String
  nMaxCustFilter As Long
  nFilterIndex As Long
  lpstrFile As String
  nMaxFile As Long
  lpstrFileTitle As String
  nMaxFileTitle As Long
  lpstrInitialDir As String
  lpstrTitle As String
  flags As Long
  nFileOffset As Integer
  nFileExtension As Integer
  lpstrDefExt As String
  lCustData As Long
  lpfnHook As Long
  lpTemplateName As String
End Type
 
Private Dlg As OPENFILENAME
Private bDialogExecuted As Boolean ' will be true if user pressed OK, false if dialog was canceled
 
' This can be used to set an initial filename before displaying the dialog
Public Property Let strFile(value As String)
  CopyMemory ByVal Dlg.lpstrFile, ByVal value, Len(value)
End Property
 
' This can be used to retrieve full path of the selected file, after dialog display.
Public Property Get strFile() As String
  strFile = Dlg.lpstrFile
End Property
 
' This can be used to get the filename (without path) of the selected file, after dialog display.
Public Property Get FileName() As String
  FileName = Dlg.lpstrFileTitle
End Property
 
Public Property Get Executed() As Boolean
  Executed = bDialogExecuted
End Property
 
' Set dialog title
Public Property Let Title(value As String)
  Dlg.lpstrTitle = value
End Property
 
' Set default file extension
Public Property Let DefaultExt(value As String)
  Dlg.lpstrDefExt = value
End Property
 
Public Property Let Filter(value As String)
  Dlg.lpstrFilter = value
End Property
 
Public Property Let Owner(value As Long)
  Dlg.hwndOwner = value
End Property
 
 
Public Sub Initialize()
  Dlg.lStructSize = Len(Dlg)
  Dlg.hInstance = App.hInstance
  Dlg.nFilterIndex = 1
  Dlg.lpstrFile = String(257, 0)
  Dlg.nMaxFile = Len(Dlg.lpstrFile) - 1
  Dlg.lpstrFileTitle = Dlg.lpstrFile
  Dlg.nMaxFileTitle = Dlg.nMaxFile
  Dlg.lpstrInitialDir = vbNullString
  Dlg.flags = 0
End Sub
 
Public Sub ShowOpenDialog()
  bDialogExecuted = GetOpenFileName(Dlg)
End Sub
 
Public Sub ShowSaveDialog()
  bDialogExecuted = GetSaveFileName(Dlg)
End Sub

VB6 | ROT-N 暗号化

VB6 の Rot-N 暗号化暗号。
非常に基本的な暗号化であり、安全な保護には信頼性がありません。

'********************************************************************************
'* Title:       ROT-N encryption module                                         *
'* Author:      Viotto                                                          *
'* Website:     www.viotto-security.net                                         *
'* Description: simple substitution cipher for bytes: each input                *
'*              byte value will be rotated by the specified number of bytes.    *
'* Purpose:     simple encryption for text and files.                           *
'* Usage:       Encryption key should be a number between 1 and 255; higher     *
'*              numbers will work but they cause redundant rotations.           *
'* Notes:       with key value 128 (ROT-128), you can use same function to      *
'*              encrypt and decrypt data. Otherwise you can use ROTN_Forward    *
'*              to encrypt and ROTN_Backward to decrypt.                        *
'*                                                                              *
'********************************************************************************

Public Function ROTN_Forward(ByVal InputData As String, ByVal NumKey As Integer) As String
Dim i As Long, OutChar As String
For i = 1 To Len(InputData)
OutChar = Asc(Mid(InputData, i, 1)) + NumKey
While OutChar > 255
OutChar = OutChar - 256
Wend
ROTN_Forward = ROTN_Forward + Chr(OutChar)
Next
End Function

Public Function ROTN_Backward(ByVal InputData As String, ByVal NumKey As Integer) As String
Dim i As Long, OutChar As String
For i = 1 To Len(InputData)
OutChar = Asc(Mid(InputData, i, 1)) - NumKey
While OutChar < 0
OutChar = OutChar + 256
Wend
ROTN_Backward = ROTN_Backward + Chr(OutChar)
Next
End Function

VB6 | デフォルトのブラウザー パスを取得する

数行のコードで、Windows API はありません。

Function DefaultBrowser() As String
  Dim regshell As Object
  Set regshell = CreateObject("Wscript.Shell")
  ' Reads the registry value where is stored the default application to use with HTTP
  DefaultBrowser = regshell.regread("HKEY_CLASSES_ROOT\HTTP\shell\open\command\")
  ' Removes shell parameters after the actual path, preserving only path included in double             ' quotes
  DefaultBrowser = Left(DefaultBrowser, InStr(1, DefaultBrowser, ".exe", vbTextCompare) + 4)
  ' Removes double quotes (")
  DefaultBrowser = Replace(DefaultBrowser, Chr(34), vbNullString)
End Function
メニュー