Nick HodgesさんがTHTMLWriterというHTMLを生成するライブラリを公開しています。
Nick Hodges | Announcing THTMLWriter
delphihtmlwriter - Project Hosting on Google Code
ライセンスはMPL 1.1となっています。Generics.Collectionsに依存しているのでDelphi 2009以降の対応になると思われます(開発そのものはDelphi 2010で行っているとのこと)。
2010年11月30日
2010年11月29日
Stuxnet
今年(2010年)の7月くらいからStuxnetと呼ばれるワーム(マルウェア)が話題になっていました。
W32.Temphid (ja) (Symantec)
Trojan-Dropper:W32/Stuxnet (F-Secure)
WORM_STUXNET.A - 概 要 (Trendmicro)
Stuxnet | ウイルス情報 | マカフィー (McAfee)
キヤノンITソリューションズ:ESET Smart Security & ESET NOD32アンチウイルス:Win32/Stuxnet.A (ESET)
Stuxnetはルートキットの特徴を持ち、複数の攻撃(感染)手段を用意していることに加え、シーメンスのSiemens SimaticというPLC(いわゆるシーケンサ - シーケンサは三菱電機株式会社の登録商標ですので、たとえとしては適切ではないかもしれませんが)にアクセスしようとする、という特徴があり、色々な憶測がなされてきました。しかしここにきて多くのセキュリティ関係者の努力により、Stuxnetの正体がほぼ解明された模様です。
エフセキュアブログ : Stuxnetに関する質疑応答
Stuxnet: 画期的な解明 | Symantec Connect
エフセキュアブログ : 「Stuxnet」再び:質疑応答
これらの情報を信じる限り、Stuxnetは西側(おそらくイスラエル)の情報機関がイランの核物質精製施設(ウラン濃縮プラント)の運用を妨害するためのもの、ということのようです。Stuxnetの備える強力な感染力は外部から直接アプローチできない施設に対して間接的に浸透するための手段ということになります。まぁイスラエルはイラクの原子炉を稼動前に爆撃で破壊(Operation Opera)していたりしますから、信じられないこともない話ですが、Stuxnetによる攻撃を考案した人は相当な切れ者だと思われます(いわゆるコロンブスの卵、ですね)。
2011/01/19追記: New York Timesが記事にしたことでまた話題になっているようです。
エフセキュアブログ : 「Stuxnet」に関する新情報
2011/02/16追記: Stuxnetの解析は続いているようです。DoDやNSAからクレームがついたりはしないんでしょうか?
エフセキュアブログ : 「Stuxnet」再び
W32.Stuxnet 調査詳細の改定版を公開 | Symantec Connect
2011/02/21追記: 2011年02月10日にJPCERT/CCが主催して行われた制御システムセキュリティカンファレンス 2011でもStuxnetが取り上げられたようです。
「Stuxnet - 制御システムを狙った初のマルウエア」 - JPCERT/CC 情報流通対策グループ 小熊 信孝
W32.Temphid (ja) (Symantec)
Trojan-Dropper:W32/Stuxnet (F-Secure)
WORM_STUXNET.A - 概 要 (Trendmicro)
Stuxnet | ウイルス情報 | マカフィー (McAfee)
キヤノンITソリューションズ:ESET Smart Security & ESET NOD32アンチウイルス:Win32/Stuxnet.A (ESET)
Stuxnetはルートキットの特徴を持ち、複数の攻撃(感染)手段を用意していることに加え、シーメンスのSiemens SimaticというPLC(いわゆるシーケンサ - シーケンサは三菱電機株式会社の登録商標ですので、たとえとしては適切ではないかもしれませんが)にアクセスしようとする、という特徴があり、色々な憶測がなされてきました。しかしここにきて多くのセキュリティ関係者の努力により、Stuxnetの正体がほぼ解明された模様です。
エフセキュアブログ : Stuxnetに関する質疑応答
Stuxnet: 画期的な解明 | Symantec Connect
エフセキュアブログ : 「Stuxnet」再び:質疑応答
これらの情報を信じる限り、Stuxnetは西側(おそらくイスラエル)の情報機関がイランの核物質精製施設(ウラン濃縮プラント)の運用を妨害するためのもの、ということのようです。Stuxnetの備える強力な感染力は外部から直接アプローチできない施設に対して間接的に浸透するための手段ということになります。まぁイスラエルはイラクの原子炉を稼動前に爆撃で破壊(Operation Opera)していたりしますから、信じられないこともない話ですが、Stuxnetによる攻撃を考案した人は相当な切れ者だと思われます(いわゆるコロンブスの卵、ですね)。
2011/01/19追記: New York Timesが記事にしたことでまた話題になっているようです。
エフセキュアブログ : 「Stuxnet」に関する新情報
2011/02/16追記: Stuxnetの解析は続いているようです。DoDやNSAからクレームがついたりはしないんでしょうか?
エフセキュアブログ : 「Stuxnet」再び
W32.Stuxnet 調査詳細の改定版を公開 | Symantec Connect
2011/02/21追記: 2011年02月10日にJPCERT/CCが主催して行われた制御システムセキュリティカンファレンス 2011でもStuxnetが取り上げられたようです。
「Stuxnet - 制御システムを狙った初のマルウエア」 - JPCERT/CC 情報流通対策グループ 小熊 信孝
2010年11月26日
Pulsar(Delphi x64)情報
Stack OverflowのHow should I prepare my 32-bit Delphi programs for an eventual 64-bit compiler?(来るべき64bitコンパイラに備えて、32bit Delphiのプログラムでどのような準備をしておくべきでしょうか?)という質問に対してBarry Kellyさんが非常に興味深い回答をしています。
てきとうな要約:
おそらくNativeInt/NativeUIntはINT_PTR/UINT_PTR(Windows Data Types)のまともな名前バージョンです(INT_PTR/UINT_PTRはそのネーミングセンスのなさで有名)。またPulsar(64bit Delphi)でBASMがサポートされない件はフォーラムのDelphi x64 and no build-in ASM = troublesでも話題になりましたが、PulsarにBASMを間に合わせるのは困難だ、という話でした。
元ねたはNick HodgesさんのFlotsam and Jetsam #15。
てきとうな要約:
- 注意書き: Barry KellyさんはEmbarcaderoに勤務していますが、Embarcaderoを代表した回答ではなく、また64bit版Delphiはこうあるべきであるという仮定に基づいたものであり、設計上異なる選択が行われることになるかもしれません。
- NativeIntとNativeUIntというプラットフォームにより32bitまたは64bitとなる整数型が用意される。これ以外の整数型はターゲットプラットフォームによりサイズが変化することはない。
- TComponent.Tagのように整数とポインタをキャストして使用するようなものはNativeInt/NativeUIntに置き換えられる。
- NativeInt/NativeUIntはポインタとの相互変換を必要とする場合以外には使用するべきではない。これ以外の整数型の変数は従来通りのサイズのものでよい。参照やTHandle、HWNDのようなものだけにNativeInt/NativeUIntを使う。
- 文字列や動的配列の(ヘッダデータのような)内部の詳細を当てにしてはいけない。
- (RTLの)APIは可能な限り32bitと64bitの間で維持する、というのが原則になる。たとえばTListの最大要素数もMaxInt div SizeOf(Pointer)のままになる。
- (RTLの)APIを64bitで拡張する場合、別のfunction/method/propertyでアクセスするようにする。たとえばLength()はそのままで、LongLength()を用意する、というように。
- これに関連してサイズを縮小する方向の変換(64bitの戻値を32bit整数の変数に代入するような)に関するエラーチェックを強化する。
- おそらく動的配列は64bitのインデックスをサポートする。
- おそらく文字列は32bitでインデックスが制限される。実際に文字列が4GBを超える状況を想定できないため。
- ほぼ確実にビルトインアセンブラ(BASM)はサポートされないが、オブジェクトファイル(.obj)のリンクはサポートされる。
おそらくNativeInt/NativeUIntはINT_PTR/UINT_PTR(Windows Data Types)のまともな名前バージョンです(INT_PTR/UINT_PTRはそのネーミングセンスのなさで有名)。またPulsar(64bit Delphi)でBASMがサポートされない件はフォーラムのDelphi x64 and no build-in ASM = troublesでも話題になりましたが、PulsarにBASMを間に合わせるのは困難だ、という話でした。
元ねたはNick HodgesさんのFlotsam and Jetsam #15。
2010年11月19日
InterBase 5/6からInterBase XEに移行するとシステムテーブルにアクセスできない問題
Support KBに
no permission for read/select access to table RDB$XXXX by user SYSDBA
という記事がありました。興味深い。とりあえずメモ。
てきとうな要約: InterBase 6.5およびそれ以前のバージョンからInterBase XEにデータベースを移行するとSYSDBAでシステムテーブル(RDB$XXXX)にアクセスできない(パーミッションがない)、という問題が発生する。この問題を解決する1番目の方法はシステムテーブルへのアクセスをgrantするもので、InterBaseのインストールフォルダの下の"examples\security\readmeta.sql"をISQLかIBConsoleから実行する。2番目の方法はパフォーマンスモニタリングのためにシステムテンポラリテーブルにアクセスしたい場合のもので、通常はSYSDBAとデータベースのオーナにのみ許可されているシステムテンポラリテーブルへのアクセスを全てのユーザに公開するようなスクリプト(元記事の"create procedure granttmp as"以下の部分)を実行する。
2016/07/17追記: Support KBの記事の日本語訳が出ています。
データベースのリストア時に発生する unassigned code エラーについて
またdocwikiにも記述があります。
移行における問題 - InterBase
no permission for read/select access to table RDB$XXXX by user SYSDBA
という記事がありました。興味深い。とりあえずメモ。
てきとうな要約: InterBase 6.5およびそれ以前のバージョンからInterBase XEにデータベースを移行するとSYSDBAでシステムテーブル(RDB$XXXX)にアクセスできない(パーミッションがない)、という問題が発生する。この問題を解決する1番目の方法はシステムテーブルへのアクセスをgrantするもので、InterBaseのインストールフォルダの下の"examples\security\readmeta.sql"をISQLかIBConsoleから実行する。2番目の方法はパフォーマンスモニタリングのためにシステムテンポラリテーブルにアクセスしたい場合のもので、通常はSYSDBAとデータベースのオーナにのみ許可されているシステムテンポラリテーブルへのアクセスを全てのユーザに公開するようなスクリプト(元記事の"create procedure granttmp as"以下の部分)を実行する。
2016/07/17追記: Support KBの記事の日本語訳が出ています。
データベースのリストア時に発生する unassigned code エラーについて
またdocwikiにも記述があります。
移行における問題 - InterBase
2010年11月16日
ダミーのDwmapi.dllを作成する
前回のアーティクルでも触れましたが、Visual Studioで作成したプログラムがWindows Vista以降で"Known DLLs"となったDwmapi.dllをWindows 2000/XPでもLoadLibraryしてしまいバイナリプランティングを引き起こしてしまう件(およびDelphiで作成したプログラムにこの問題が存在しない件)について、これを検証するためのダミーのDwmapi.dllを作成してみました(当然Windows 2000/XP用です)。
まずはプロジェクトファイルです。DLLを新規作成し、DWMAPIという名前にします。
元ねたはVS2010 でコンパイルされた全ての単体 MFC アプリケーションに脆弱性が存在 - スラッシュドット・ジャパン、VS2010でコンパイルされたすべてのMFCアプリに脆弱性ってのは過小報告? - Windows 2000 Blog。
まずはプロジェクトファイルです。DLLを新規作成し、DWMAPIという名前にします。
library DWMAPI;
uses
Windows,
SysUtils,
Classes,
_DWMAPI in '_DWMAPI.pas';
exports
DwmDefWindowProc,
DwmEnableBlurBehindWindow,
DwmEnableComposition,
DwmEnableMMCSS,
DwmExtendFrameIntoClientArea,
DwmGetColorizationColor,
DwmGetCompositionTimingInfo,
DwmGetWindowAttribute,
DwmIsCompositionEnabled,
DwmModifyPreviousDxFrameDuration,
DwmQueryThumbnailSourceSize,
DwmRegisterThumbnail,
DwmSetDxFrameDuration,
DwmSetPresentParameters,
DwmSetWindowAttribute,
DwmUnregisterThumbnail,
DwmUpdateThumbnailProperties;
{$R *.res}
begin
end.
さらに新規作成でユニットを追加し、_DWMAPI.pasとします。unit _DWMAPI;
interface
uses
Types;
type
DWORD = Types.DWORD;
{$EXTERNALSYM DWORD}
BOOL = LongBool;
{$EXTERNALSYM BOOL}
UINT = LongWord;
{$EXTERNALSYM UINT}
HRGN = type LongWord;
{$EXTERNALSYM HRGN}
LONGLONG = Int64;
{$EXTERNALSYM LONGLONG}
ULONGLONG = UInt64;
{$EXTERNALSYM ULONGLONG}
ULARGE_INTEGER = record
case Integer of
0: (
LowPart: DWORD;
HighPart: DWORD);
1: (
QuadPart: LONGLONG);
end;
{$EXTERNALSYM ULARGE_INTEGER}
PULargeInteger = ^TULargeInteger;
TULargeInteger = ULARGE_INTEGER;
HWND = type LongWord;
{$EXTERNALSYM HWND}
WPARAM = Longint;
{$EXTERNALSYM WPARAM}
LPARAM = Longint;
{$EXTERNALSYM LPARAM}
LRESULT = Longint;
{$EXTERNALSYM LRESULT}
{$EXTERNALSYM PDWM_BLURBEHIND}
PDWM_BLURBEHIND = ^DWM_BLURBEHIND;
{$EXTERNALSYM DWM_BLURBEHIND}
DWM_BLURBEHIND = packed record
dwFlags: DWORD;
fEnable: BOOL;
hRgnBlur: HRGN;
fTransitionOnMaximized: BOOL;
end;
_DWM_BLURBEHIND = DWM_BLURBEHIND;
TDWMBlurBehind = DWM_BLURBEHIND;
PDWMBlurBehind = ^TDWMBlurBehind;
_MARGINS = record
cxLeftWidth: Integer;
cxRightWidth: Integer;
cyTopHeight: Integer;
cyBottomHeight: Integer;
end;
{$EXTERNALSYM _MARGINS}
MARGINS = _MARGINS;
{$EXTERNALSYM MARGINS}
PMARGINS = ^MARGINS;
{$EXTERNALSYM PMARGINS}
TMargins = MARGINS;
{$EXTERNALSYM PDWM_THUMBNAIL_PROPERTIES}
PDWM_THUMBNAIL_PROPERTIES = ^DWM_THUMBNAIL_PROPERTIES;
{$EXTERNALSYM DWM_THUMBNAIL_PROPERTIES}
DWM_THUMBNAIL_PROPERTIES = packed record
dwFlags: DWORD;
rcDestination: TRect;
rcSource: TRect;
opacity: Byte;
fVisible: BOOL;
fSourceClientAreaOnly: BOOL;
end;
_DWM_THUMBNAIL_PROPERTIES = DWM_THUMBNAIL_PROPERTIES;
TDWMThumbnailProperties = DWM_THUMBNAIL_PROPERTIES;
PDWMThumbnailProperties = ^TDWMThumbnailProperties;
{$EXTERNALSYM DWM_FRAME_COUNT}
DWM_FRAME_COUNT = ULONGLONG;
{$EXTERNALSYM QPC_TIME}
QPC_TIME = ULONGLONG;
{$EXTERNALSYM UNSIGNED_RATIO}
UNSIGNED_RATIO = packed record
uiNumerator: Cardinal;
uiDenominator: Cardinal;
end;
_UNSIGNED_RATIO = UNSIGNED_RATIO;
TUnsignedRatio = UNSIGNED_RATIO;
PUnsignedRatio = ^TUnsignedRatio;
{$EXTERNALSYM DWM_TIMING_INFO}
DWM_TIMING_INFO = packed record
cbSize: Cardinal;
rateRefresh: UNSIGNED_RATIO;
qpcRefreshPeriod: QPC_TIME;
rateCompose: UNSIGNED_RATIO;
qpcVBlank: QPC_TIME;
cRefresh: DWM_FRAME_COUNT;
cDXRefresh: UINT;
qpcCompose: QPC_TIME;
cFrame: DWM_FRAME_COUNT;
cDXPresent: UINT;
cRefreshFrame: DWM_FRAME_COUNT;
cFrameSubmitted: DWM_FRAME_COUNT;
cDXPresentSubmitted: UINT;
cFrameConfirmed: DWM_FRAME_COUNT;
cDXPresentConfirmed: UINT;
cRefreshConfirmed: DWM_FRAME_COUNT;
cDXRefreshConfirmed: UINT;
cFramesLate: DWM_FRAME_COUNT;
cFramesOutstanding: UINT;
cFrameDisplayed: DWM_FRAME_COUNT;
qpcFrameDisplayed: QPC_TIME;
cRefreshFrameDisplayed: DWM_FRAME_COUNT;
cFrameComplete: DWM_FRAME_COUNT;
qpcFrameComplete: QPC_TIME;
cFramePending: DWM_FRAME_COUNT;
qpcFramePending: QPC_TIME;
cFramesDisplayed: DWM_FRAME_COUNT;
cFramesComplete: DWM_FRAME_COUNT;
cFramesPending: DWM_FRAME_COUNT;
cFramesAvailable: DWM_FRAME_COUNT;
cFramesDropped: DWM_FRAME_COUNT;
cFramesMissed: DWM_FRAME_COUNT;
cRefreshNextDisplayed: DWM_FRAME_COUNT;
cRefreshNextPresented: DWM_FRAME_COUNT;
cRefreshesDisplayed: DWM_FRAME_COUNT;
cRefreshesPresented: DWM_FRAME_COUNT;
cRefreshStarted: DWM_FRAME_COUNT;
cPixelsReceived: ULONGLONG;
cPixelsDrawn: ULONGLONG;
cBuffersEmpty: DWM_FRAME_COUNT;
end;
_DWM_TIMING_INFO = DWM_TIMING_INFO;
TDWMTimingInfo = DWM_TIMING_INFO;
PDWMTimingInfo = ^TDWMTimingInfo;
{$EXTERNALSYM HTHUMBNAIL}
HTHUMBNAIL = THandle;
{$EXTERNALSYM PHTHUMBNAIL}
PHTHUMBNAIL = ^HTHUMBNAIL;
{$EXTERNALSYM DWM_PRESENT_PARAMETERS}
DWM_PRESENT_PARAMETERS = packed record
cbSize: Cardinal;
fQueue: BOOL;
cRefreshStart: DWM_FRAME_COUNT;
cBuffer: UINT;
fUseSourceRate: BOOL;
rateSource: UNSIGNED_RATIO;
cRefreshesPerFrame: UINT;
eSampling: UINT;
end;
_DWM_PRESENT_PARAMETERS = DWM_PRESENT_PARAMETERS;
TDWMPresentParameters = DWM_PRESENT_PARAMETERS;
PDWMPresentParameters = ^TDWMPresentParameters;
function DwmDefWindowProc(hWnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM; var plResult: LRESULT): BOOL; stdcall;
function DwmEnableBlurBehindWindow(hWnd: HWND; const pBlurBehind: TDWMBlurBehind): HResult; stdcall;
function DwmEnableComposition(uCompositionAction: UINT): HResult; stdcall;
function DwmEnableMMCSS(fEnableMMCSS: BOOL): HResult; stdcall;
function DwmExtendFrameIntoClientArea(hWnd: HWND; const pMarInset: TMargins): HResult; stdcall;
function DwmGetColorizationColor(out pcrColorization: DWORD; out pfOpaqueBlend: BOOL): HResult; stdcall;
function DwmGetCompositionTimingInfo(hwnd: HWND; out pTimingInfo: TDWMTimingInfo): HResult; stdcall;
function DwmGetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall;
function DwmIsCompositionEnabled(out pfEnabled: BOOL): HResult; stdcall;
function DwmModifyPreviousDxFrameDuration(hwnd: HWND; cRefreshes: Integer; fRelative: BOOL): HResult; stdcall;
function DwmQueryThumbnailSourceSize(hThumbnail: HTHUMBNAIL; pSize: PSIZE): HResult; stdcall;
function DwmRegisterThumbnail(hwndDestination: HWND; hwndSource: HWND; out phThumbnailId: HTHUMBNAIL): HResult; stdcall;
function DwmSetDxFrameDuration(hwnd: HWND; cRefreshes: Integer): HResult; stdcall;
function DwmSetPresentParameters(hwnd: HWND; var pPresentParams: TDWMPresentParameters): HResult; stdcall;
function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall;
function DwmUnregisterThumbnail(hThumbnailId: HTHUMBNAIL): HResult; stdcall;
function DwmUpdateThumbnailProperties(hThumbnailId: HTHUMBNAIL; const ptnProperties: TDWMThumbnailProperties): HResult; stdcall;
implementation
function DwmDefWindowProc(hWnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM; var plResult: LRESULT): BOOL;
begin
Result := False;
end;
function DwmEnableBlurBehindWindow(hWnd: HWND; const pBlurBehind: TDWMBlurBehind): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmEnableComposition(uCompositionAction: UINT): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmEnableMMCSS(fEnableMMCSS: BOOL): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmExtendFrameIntoClientArea(hWnd: HWND; const pMarInset: TMargins): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmGetColorizationColor(out pcrColorization: DWORD; out pfOpaqueBlend: BOOL): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmGetCompositionTimingInfo(hwnd: HWND; out pTimingInfo: TDWMTimingInfo): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmGetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmIsCompositionEnabled(out pfEnabled: BOOL): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmModifyPreviousDxFrameDuration(hwnd: HWND; cRefreshes: Integer; fRelative: BOOL): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmQueryThumbnailSourceSize(hThumbnail: HTHUMBNAIL; pSize: PSIZE): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmRegisterThumbnail(hwndDestination: HWND; hwndSource: HWND; out phThumbnailId: HTHUMBNAIL): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmSetDxFrameDuration(hwnd: HWND; cRefreshes: Integer): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmSetPresentParameters(hwnd: HWND; var pPresentParams: TDWMPresentParameters): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmUnregisterThumbnail(hThumbnailId: HTHUMBNAIL): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
function DwmUpdateThumbnailProperties(hThumbnailId: HTHUMBNAIL; const ptnProperties: TDWMThumbnailProperties): HResult; stdcall;
begin
Result := E_NOTIMPL;
end;
end.
(Dwmapi.dll関係の各種定義はDwmApi.pasなどから借りてきました)。これでビルドしたDwmapi.dllをWindows 2000/XPでSystem32あたりに配置しておきます。この状態から問題のありそうなプログラムを実行してDependency WalkerやWindows SysInternalsのProcess Explorerなどを使ってDwmapi.dllのロード状況を確認することができます。確かにDelphiで作成したプログラムは問題ないようですね。念のためにVCLのソースで確認してみると、DWMのデスクトップコンポジションを使用できるかどうかを調べるDwmApiユニットのDwmCompositionEnabled関数(ヘルプにはエントリがありませんが)の実装がfunction DwmCompositionEnabled: Boolean;
var
LEnabled: BOOL;
begin
Result := (Win32MajorVersion >= 6) and (DwmIsCompositionEnabled(LEnabled) = S_OK) and LEnabled;
end;
(Delphi 20007のDwmApi.pasの795行目から)となっており、Windows Vista以降かどうかの確認を正しく行っていることがわかります。元ねたはVS2010 でコンパイルされた全ての単体 MFC アプリケーションに脆弱性が存在 - スラッシュドット・ジャパン、VS2010でコンパイルされたすべてのMFCアプリに脆弱性ってのは過小報告? - Windows 2000 Blog。
2010年11月15日
バイナリプランティングの防止
IPAからも注意喚起が行われていますが、最近バイナリプランティング("Binary planting"、あるいは"DLL planting"、"DLL preloading"とも表現されます)という攻撃手法が問題になっています。これは(いわゆる"Known DLLs"を除く)絶対パス指定ではないDLLを検索するパスに"カレントディレクトリ"が含まれていて、状況によってはその優先順位が高いために攻撃者の用意した不正なDLLが実行プログラムにバインドされてしまう(通常はDLLをロードして初期化するだけでDLLMainが実行されてしまいますから、この時点で攻撃成立です)、というものです(これがが狭義の"DLL planting")。また類似の状況として、絶対パス指定ではない実行ファイルをCreateProcess/CreateProcessAsUser/CreateProcessWithLogonW/CreateProcessWithTokenW/ShellExecute/ShellExecuteExなどで起動することでも同様の問題が生じます。さらに問題を複雑なものにする要因として、Windows Vista/7ではKnown DLLsに含まれるDwmapi.dllがWindows 2000/XPには存在しないにもかかわらず一部のフレームワークがWindowsのバージョンを考慮せずにDwmapi.dllをロードしようとするために、カレントディレクトリに攻撃用のDwmapi.dllを配置することでこれがバインドされてしまい攻撃が成立してしまう、というものがあります(幸いにもVCLや.NET Frameworkは該当しませんが、MFC(Visual Studio 2005/2008/2010)は該当するようです)。上記のいずれの状況でも攻撃用のDLL/EXEはカレントディレクトリに配置するのが攻撃成立の条件になります(例えばSystem32にそんなものを置かれるようではどんな攻撃も可能ですから)ので、カレントディレクトリが外部に設定されてプログラムが起動するような場合、つまりファイルをダブルクリックして関連付けでプログラムが起動するような場合が最も危険である、ということになります(ショートカットでもカレントディレクトリは設定できますが)。
バイナリプランティングをプログラム側から防ぐには、
ということでSetDllDirectoryを使用してDLLの検索パスからカレントディレクトリを削除するサンプルです。なるべく早い時点で設定するのが望ましいので、プロジェクトファイルの先頭で行います。またSetDllDirectoryはWindows XP SP1以降にしか存在しないので、エントリの存在を確認して呼び出すようにしています。
元ねたは以下の通り。
情報処理推進機構(IPA)マイクロソフト
バイナリプランティングをプログラム側から防ぐには、
- リンクするDLLや起動する実行ファイルは可能な限り完全修飾パス名を使用する。
- SetDllDirectoryで""(空文字列)を指定してDLLの検索パスからカレントディレクトリを削除する(Windows XP以降)。
- DLL/実行ファイルを検索するのにSearchPath (ja)はなるべく使用しない。使用するときはSetSearchPathModeでBASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODEを設定する(Windows Vista以降)。
- Windowsの特定のバージョン以降で"Known DLLs"に追加されたDLLをLoadLibraryするときはWindowsのバージョンチェックを行うか、完全修飾パス名を使用する。
ということでSetDllDirectoryを使用してDLLの検索パスからカレントディレクトリを削除するサンプルです。なるべく早い時点で設定するのが望ましいので、プロジェクトファイルの先頭で行います。またSetDllDirectoryはWindows XP SP1以降にしか存在しないので、エントリの存在を確認して呼び出すようにしています。
program Project1;
uses
Windows,
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
type
TSetDllDirectoryFunc = function (lpPathName: PChar): BOOL; stdcall;
const
{$IFDEF Unicode}
CSetDllDirectory = 'SetDllDirectoryW';
{$ELSE}
CSetDllDirectory = 'SetDllDirectoryA';
{$ENDIF}
var
S: String;
SetDllDirectory: TSetDllDirectoryFunc;
begin
@SetDllDirectory := GetProcAddress(GetModuleHandle(kernel32),
CSetDllDirectory);
if Assigned(SetDllDirectory) = True then
begin
S := '#0';
SetDllDirectory(PChar(S));
end;
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
なおコンソールアプリケーションでグラスエフェクトを有効にするのサンプルコードもDwmapi.dllがWindows 2000/XPには存在しないことを利用したバイナリプランティングの影響を受けるため、修正してあります。元ねたは以下の通り。
情報処理推進機構(IPA)マイクロソフト
- マイクロソフト セキュリティ アドバイザリ (2269637): 安全でないライブラリのロードにより、リモートでコードが実行される
- Dynamic-Link Library セキュリティ (Windows)
- Dynamic-Link Library Search Order (Windows)
- WindowsのDLLだけが危ないのか? DLL hijacking vulnerability概説(前編)(1/2)
- WindowsのDLLだけが危ないのか? DLL hijacking vulnerability概説(後編)(1/3)
2010年11月13日
Delphi/C++Builder XE Update Pack 1
Delphi/C++Builder XEのUpdate Pack 1がリリースされています。Update Pack 1にはDelphi/C++Builder XEのUpdate 1、Help Update 1、Boost Update 1の3つが含まれています。
28116 Update Pack 1 for Delphi XE and C++Builder XE
リリース ノート: Delphi XE および C++Builder XE Update 1
List of Bug Fixes in Delphi and C++Builder XE Update 1
なおAndreas HausladenさんによるとUpdate 1を適用するとDDevExtensionsがcrackとみなされて動作しないとのことです。
XE Update 1 the death of DDevExtensions | Andy’s Blog and Tools
2010/11/14追記: Help Update 1を適用するとPSDKのコンテンツが削除される、という問題が報告されています。この場合はHelpそのものを一旦アンインストールし、ダウンロードして展開したHelp Update1のセットアップからPSDKを含めてインストールすることで回避できるようです。
2010/11/14追記: 今回のUpdate 1のリリース日についてですが、1年前のこの話はNickさんが辞めることでなかったことになってしまったのでしょうかね?国別ではなくワールドワイドで同時展開するにはよいポリシーだと思うのですが…。
2010/11/14追記: Update 1適用後にAndreas HausladenさんのDDevExtensionsが動作しない件についてですが、原因が判明して問題を回避したDDevExtensions 2.1 for XE Update 1がリリースされています。
DDevExtensions for XE Update 1 resurrection | Andy’s Blog and Tools
2010/11/16追記: A7MさんによるとC++Builder XEにBoost Update 1を適用後にboost::tupleを使用している箇所がコンパイルエラーになるという問題があり、ソースコードを修正することで回避できるとのことです。
Update Pack 1 for C++Builder XEのBoost Update 1についてのちょっとした注意 - C++Builder好きの秘密基地
2010/11/17追記: Team Japanにも関連記事が出ています。
Team Japan » RAD Studio/C++Builder/Delphi XE Update 1
28116 Update Pack 1 for Delphi XE and C++Builder XE
リリース ノート: Delphi XE および C++Builder XE Update 1
List of Bug Fixes in Delphi and C++Builder XE Update 1
なおAndreas HausladenさんによるとUpdate 1を適用するとDDevExtensionsがcrackとみなされて動作しないとのことです。
XE Update 1 the death of DDevExtensions | Andy’s Blog and Tools
2010/11/14追記: Help Update 1を適用するとPSDKのコンテンツが削除される、という問題が報告されています。この場合はHelpそのものを一旦アンインストールし、ダウンロードして展開したHelp Update1のセットアップからPSDKを含めてインストールすることで回避できるようです。
2010/11/14追記: 今回のUpdate 1のリリース日についてですが、1年前のこの話はNickさんが辞めることでなかったことになってしまったのでしょうかね?国別ではなくワールドワイドで同時展開するにはよいポリシーだと思うのですが…。
2010/11/14追記: Update 1適用後にAndreas HausladenさんのDDevExtensionsが動作しない件についてですが、原因が判明して問題を回避したDDevExtensions 2.1 for XE Update 1がリリースされています。
DDevExtensions for XE Update 1 resurrection | Andy’s Blog and Tools
2010/11/16追記: A7MさんによるとC++Builder XEにBoost Update 1を適用後にboost::tupleを使用している箇所がコンパイルエラーになるという問題があり、ソースコードを修正することで回避できるとのことです。
Update Pack 1 for C++Builder XEのBoost Update 1についてのちょっとした注意 - C++Builder好きの秘密基地
2010/11/17追記: Team Japanにも関連記事が出ています。
Team Japan » RAD Studio/C++Builder/Delphi XE Update 1
2010年11月12日
Firebird 2.xから2.5へのバージョンアップ時のユーザデータベースの移行
Firebird 2.xで運用しているシステムを2.5にバージョンアップするときにはユーザデータベース(security2.fdb)の移行に気をつけましょう、という記事。
Firebird News » Migrating users from FB 2.1 to FB 2.5
てきとうな要約: ユーザデータベースもまたFirebirdのデータベースなので、Firebirdのバージョンが異なるとODSのバージョンもまた異なる、という問題があるため、単にコピーしておいたsecurity2.fdbを上書きするようなやり方は無保証であり、gbakでバックアップ/リストアするのが望ましいけれども、この場合新しい"RDB$ADMIN"ロールとの関係で、ユーザ操作を行う新しいSQL(CREATE/ALTER/DROP USER)をSYSDBAを含む通常ユーザが実行できない、ということになる(Firebird 2.5.1にはこの問題を解決するスクリプトが含まれる予定)。結局現時点ではgsecを使って新しくユーザを登録しなおすのが最も望ましい解決方法、ということになる。
Firebird News » Migrating users from FB 2.1 to FB 2.5
てきとうな要約: ユーザデータベースもまたFirebirdのデータベースなので、Firebirdのバージョンが異なるとODSのバージョンもまた異なる、という問題があるため、単にコピーしておいたsecurity2.fdbを上書きするようなやり方は無保証であり、gbakでバックアップ/リストアするのが望ましいけれども、この場合新しい"RDB$ADMIN"ロールとの関係で、ユーザ操作を行う新しいSQL(CREATE/ALTER/DROP USER)をSYSDBAを含む通常ユーザが実行できない、ということになる(Firebird 2.5.1にはこの問題を解決するスクリプトが含まれる予定)。結局現時点ではgsecを使って新しくユーザを登録しなおすのが最も望ましい解決方法、ということになる。
2010年11月11日
登録回数の上限をwebから変更できなくなった
以前はインストール数の上限に達したときはwebから上限を変更できましたが、つ4さんのとほほな日々 備忘録の[Delphi] RAD XE インストールのトラブルのコメント欄や公式フォーラムのLicense bumping-What is the limit ?のJan Derkさんの発言にあるように、2010/10/05以降はwebからの変更(bump up)は動作しておらず、Support KBのインストール・使用許諾にあるとおり、インストール・使用許諾から申請するように変更されています。
2010年11月10日
2010年11月9日
Dependency Walker
実行ファイルが静的、動的にリンクしているDLLを確認するツールとしてはMicrosoft Visual Studioに付属している(た)Dependency Walkerが一般的ですが、Dependency Walkerが知らないうちにfreewareになっていました(現在はSteve P. Millerさんがメンテナのようです)。
Dependency Walker (depends.exe) Home Page
現時点の最新版は2.2.6000で、x86/x64/IA64版が用意されています。
またx86版については黒翼猫さんが日本語化パッチを作成してくださっています。
Dependency Walker 日本語化パッチ を作りました - Windows 2000 Blog
Dependency Walker (depends.exe) Home Page
現時点の最新版は2.2.6000で、x86/x64/IA64版が用意されています。
またx86版については黒翼猫さんが日本語化パッチを作成してくださっています。
Dependency Walker 日本語化パッチ を作りました - Windows 2000 Blog
2010年11月8日
IDE Fix Pack 4.0 Beta版テスト中
Andreas HausladenさんのIDE Fix Pack 4.0とDelphiSpeedUp 3.0のBeta版が公開されています(
The IDEFixPack 4.0 BETA begins… | Andy’s Blog and Tools
Delphi 7はDelphiSpeedUp(3.0 Beta)のみ、Delphi 2007はDelphiSpeedUp(3.0 Beta)+IDE Fix Pack (4.0 Beta)、Delphi 2009/2010/XEはIDE Fix Pack(4.0 Beta)のみ、とちょっと複雑です。また結構な勢いで更新されていて、まだまだ安定しているとまではいえないようです(手元の環境でもエラーが出たり…)。
2010/11/16追記: Release Candidate 2まで進んでいます。
Use it at your own risk.です)。
The IDEFixPack 4.0 BETA begins… | Andy’s Blog and Tools
Delphi 7はDelphiSpeedUp(3.0 Beta)のみ、Delphi 2007はDelphiSpeedUp(3.0 Beta)+IDE Fix Pack (4.0 Beta)、Delphi 2009/2010/XEはIDE Fix Pack(4.0 Beta)のみ、とちょっと複雑です。また結構な勢いで更新されていて、まだまだ安定しているとまではいえないようです(手元の環境でもエラーが出たり…)。
2010/11/16追記: Release Candidate 2まで進んでいます。
2010年11月5日
インストールされているDelphiのバージョンを調べる
RRUZ(Rodrigo Ruz)さんによるインストール済のDelphiのバージョンを調べる方法。レジストリのHKCUかHKLMのSoftware\Borland|CodeGear|Embarcadero\Delphi|BDS\の存在を見ればよい。それ以上何もないのでリンクのみメモ。
Detecting installed delphi versions. « The Road to Delphi – a Blog About Delphi Programming (mostly)
Detecting installed delphi versions. « The Road to Delphi – a Blog About Delphi Programming (mostly)
2010年11月4日
$WARNによる警告の制御
Delphiではコンパイラディレクティブ$WARNを使用して警告を有効/無効/エラーに昇格/デフォルトに戻すという指定をすることができます(エラーに昇格、デフォルトに戻すの2つはDelphi 2009以降の新機能)。
ONを指定するとその警告が有効に、OFFで無効に、ERRORでその警告をエラーに昇格、DEFAULTで指定をプロジェクトオプションで指定したものに戻す、という動作になります。
指定可能な警告とエラーコードは以下のとおりです。
元ねたはSource\ToolsAPI\DCCStrs.pas、警告メッセージ(Delphi) - RAD Studio (en)、エラーと警告のメッセージ(Delphi) - RAD Studio (en)。
2016/04/28追記: Delphi 10.1 Berlinの情報を追加。
2017/04/04追記: Delphi 10.2 Tokyoで追加されたW1071/W1072/W1073の情報を追加。
2018/12/01追記: Delphi 10.3 Rioで追加されたW1074の情報を追加。
2019/02/27追記: W1067/W1069/W1070/W1071/W1072/W1073のリンクを追加。
2023/11/09追記: W1074のリンクを追加。
{$WARN identifier ON | OFF | ERROR | DEFAULT}
指定可能な警告とエラーコードは以下のとおりです。
- SYMBOL_DEPRECATED
- W1000 (ja)
- SYMBOL_LIBRARY
- W1001 (ja)
- SYMBOL_PLATFORM
- W1002 (ja)
- SYMBOL_EXPERIMENTAL
- W1003 (ja)
- UNIT_LIBRARY
- W1004 (ja)
- UNIT_PLATFORM
- W1005 (ja)
- UNIT_DEPRECATED
- W1006 (ja)
- UNIT_EXPERIMENTAL
- W1007 (ja)
- HRESULT_COMPAT
- W1008 (ja)
- HIDING_MEMBER
- W1009 (ja)
- HIDDEN_VIRTUAL
- W1010 (ja)
- GARBAGE
- W1011 (ja)
- BOUNDS_ERROR
- x1012 (ja)
- ZERO_NIL_COMPAT
- W1013 (ja)
- STRING_CONST_TRUNCED
- W1014 (ja)
- FOR_LOOP_VAR_VARPAR
- W1015 (ja)
- TYPED_CONST_VARPAR
- W1016 (ja)
- ASG_TO_TYPED_CONST
- W1017 (ja)
- CASE_LABEL_RANGE
- W1018 (ja)
- FOR_VARIABLE
- x1019 (ja)
- CONSTRUCTING_ABSTRACT
- x1020 (ja)
- COMPARISON_FALSE
- W1021 (ja)
- COMPARISON_TRUE
- W1022 (ja)
- COMPARING_SIGNED_UNSIGNED
- W1023 (ja)
- COMBINING_SIGNED_UNSIGNED
- W1024 (ja)
- UNSUPPORTED_CONSTRUCT
- x1025 (ja)
- FILE_OPEN
- x1026 (ja)
- FILE_OPEN_UNITSRC
- F1027 (ja)
- BAD_GLOBAL_SYMBOL
- x1028 (ja)
- DUPLICATE_CTOR_DTOR
- W1029 (ja)
- INVALID_DIRECTIVE
- x1030 (ja)
- PACKAGE_NO_LINK
- W1031 (ja)
- PACKAGED_THREADVAR
- W1032 (ja)
- IMPLICIT_IMPORT
- x1033 (ja)
- HPPEMIT_IGNORED
- W1034 (ja)
- NO_RETVAL
- W1035 (ja)
- USE_BEFORE_DEF
- W1036 (ja)
- FOR_LOOP_VAR_UNDEF
- W1037 (ja)
- UNIT_NAME_MISMATCH
- E1038 (ja)
- NO_CFG_FILE_FOUND
- W1039 (ja)
- IMPLICIT_VARIANTS
- W1040 (ja)
- UNICODE_TO_LOCALE
- W1041 (ja)
- LOCALE_TO_UNICODE
- W1042 (ja)
- IMAGEBASE_MULTIPLE
- W1043 (ja)
- SUSPICIOUS_TYPECAST
- W1044 (ja)
- PRIVATE_PROPACCESSOR
- W1045 (ja)
- UNSAFE_TYPE
- W1046 (ja)
- UNSAFE_CODE
- W1047 (ja)
- UNSAFE_CAST
- W1048 (ja)
- OPTION_TRUNCATED
- W1049 (ja)
- WIDECHAR_REDUCED
- W1050 (ja)
- DUPLICATES_IGNORED
- W1051 (ja)
- UNIT_INIT_SEQ
- W1052 (ja)
- LOCAL_PINVOKE
- W1053 (ja)
- MESSAGE_DIRECTIVE
- x1054 (ja)
- TYPEINFO_IMPLICITLY_ADDED
- W1055 (ja)
- RLINK_WARNING
- x1056 (ja)
- IMPLICIT_STRING_CAST
- W1057 (ja)
- IMPLICIT_STRING_CAST_LOSS
- W1058 (ja)
- EXPLICIT_STRING_CAST
- W1059 (ja)
- EXPLICIT_STRING_CAST_LOSS
- W1060 (ja)
- CVT_WCHAR_TO_ACHAR
- W1061 (ja)
- CVT_NARROWING_STRING_LOST
- W1062 (ja)
- CVT_ACHAR_TO_WCHAR
- W1063 (ja)
- CVT_WIDENING_STRING_LOST
- W1064 (ja)
- NON_PORTABLE_TYPECAST
- W1065 (ja)
- LOST_EXTENDED_PRECISION
- W1066 (ja)
- LNKDFM_NOTFOUND
- W1067 (ja)
- IMMUTABLE_STRINGS
- W1068 (ja)
- MOBILE_DELPHI
- W1069 (ja)
- UNSAFE_VOID_POINTER
- W1070 (ja)
- IMPLICIT_INTEGER_CAST_LOSS
- W1071 (ja)
- IMPLICIT_CONVERSION_LOSS
- W1072 (ja)
- COMBINING_SIGNED_UNSIGNED64
- W1073 (ja)
- UNKNOWN_CUSTOM_ATTRIBUTE
- W1074 (ja)
- XML_WHITESPACE_NOT_ALLOWED
- W1201 (ja)
- XML_UNKNOWN_ENTITY
- W1202 (ja)
- XML_INVALID_NAME_START
- W1203 (ja)
- XML_INVALID_NAME
- W1204 (ja)
- XML_EXPECTED_CHARACTER
- W1205 (ja)
- XML_CREF_NO_RESOLVE
- W1206 (ja)
- XML_NO_PARM
- W1207 (ja)
- XML_NO_MATCHING_PARM
- W1208 (ja)
2016/04/28追記: Delphi 10.1 Berlinの情報を追加。
2017/04/04追記: Delphi 10.2 Tokyoで追加されたW1071/W1072/W1073の情報を追加。
2018/12/01追記: Delphi 10.3 Rioで追加されたW1074の情報を追加。
2019/02/27追記: W1067/W1069/W1070/W1071/W1072/W1073のリンクを追加。
2023/11/09追記: W1074のリンクを追加。
2010年11月2日
第18回エンバカデロ・デベロッパーキャンプ開催決定
第18回エンバカデロ・デベロッパーキャンプは(かねてからの予告どおり)2010年12月07日に開催されます。
エンバカデロ・デベロッパーキャンプ
またT6セッション『ライトニングトーク「共有!みんなの開発事例、開発経験、 テクニック」』のスピーカを募集しています。
【募集】第18回 エンバカデロ・デベロッパーキャンプ - ライトニングトークスピーカー
2010/11/04追記: ライトニングトークに高橋さんが参戦するようです。
Team Japan » ライトニングトークで喋ってみませんか?
ん~。いいネタを思いつかないし、ネタから考えるには仕事が忙しい気がするし…。
2010/11/10追記: 今回はUStreamとLiveMeeting(事前登録はここから)の両方で中継するそうです。あれ、エンバカデロ本社の誰かがCodeRage 5の後で次回からLiveMeetingはやめて他のシステムを使うようなことをいっていたような(クロスプラットフォームといいながらMac/Linuxで見られないのはいかがなものかという話の流れで)。
2010/11/19追記: UStreamでMalcolm Grovesさん出演の事前放送が行われるとのことです。
2010/11/25 17:00-17:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第1回
2010/11/26 12:00-12:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第1回(再放送) (リンク先の日付が11/19になっていますが、11/26が正しいはず)
2010/11/27追記: Team Japanに関連アーティクルが出ています。
Team Japan » 12月7日は第18回 エンバカデロ・デベロッパーキャンプです
2010/11/30追記: UStreamでJason Tiretさん出演の事前放送が行われます。
2010/12/02 17:00-17:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第2回
2010/12/03 12:00-12:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第2回(再放送)
2010/12/02 追記: Team Japanに会場へのアクセスについてのアーティクルが出ています。
Team Japan » 第18回 エンバカデロ・デベロッパーキャンプ会場へのアクセス
エンバカデロ・デベロッパーキャンプ
またT6セッション『ライトニングトーク「共有!みんなの開発事例、開発経験、 テクニック」』のスピーカを募集しています。
【募集】第18回 エンバカデロ・デベロッパーキャンプ - ライトニングトークスピーカー
2010/11/04追記: ライトニングトークに高橋さんが参戦するようです。
Team Japan » ライトニングトークで喋ってみませんか?
ん~。いいネタを思いつかないし、ネタから考えるには仕事が忙しい気がするし…。
2010/11/10追記: 今回はUStreamとLiveMeeting(事前登録はここから)の両方で中継するそうです。あれ、エンバカデロ本社の誰かがCodeRage 5の後で次回からLiveMeetingはやめて他のシステムを使うようなことをいっていたような(クロスプラットフォームといいながらMac/Linuxで見られないのはいかがなものかという話の流れで)。
2010/11/19追記: UStreamでMalcolm Grovesさん出演の事前放送が行われるとのことです。
2010/11/25 17:00-17:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第1回
2010/11/26 12:00-12:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第1回(再放送) (リンク先の日付が11/19になっていますが、11/26が正しいはず)
2010/11/27追記: Team Japanに関連アーティクルが出ています。
Team Japan » 12月7日は第18回 エンバカデロ・デベロッパーキャンプです
2010/11/30追記: UStreamでJason Tiretさん出演の事前放送が行われます。
2010/12/02 17:00-17:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第2回
2010/12/03 12:00-12:15(JST) 12月7日まで待てない!デベロッパーキャンプ事前放送 - 第2回(再放送)
2010/12/02 追記: Team Japanに会場へのアクセスについてのアーティクルが出ています。
Team Japan » 第18回 エンバカデロ・デベロッパーキャンプ会場へのアクセス
2010年11月1日
登録:
投稿 (Atom)